T-SQL COALESCE GROUPING SETS в один столбец без дубликатов NULL - PullRequest
3 голосов
/ 10 июня 2011

База данных тезауруса, в которой термины и категории связаны друг с другом и работают под управлением SQL Server 2008. Основываясь на этом и этом ответах. Вот образец:

CREATE TABLE #term (termid VARCHAR(8), en VARCHAR(32), enscope VARCHAR(32))
CREATE TABLE #link (linkid VARCHAR(10), termid VARCHAR(8), reltype VARCHAR(2), refid VARCHAR(8))
CREATE TABLE #categorylink (code VARCHAR(3), termid VARCHAR(8))

INSERT INTO #term VALUES ('100', 'ABC', 'abc_scopenote')
INSERT INTO #term VALUES ('120', 'DEF', 'def_scopenote')
INSERT INTO #term VALUES ('150', 'GHI', NULL)

INSERT INTO #link VALUES ('1', '100', 'NT', '120')
INSERT INTO #link VALUES ('2', '100', 'NT', '150')
INSERT INTO #link VALUES ('3', '120', 'BT', '100')
INSERT INTO #link VALUES ('4', '120', 'RT', '150')
INSERT INTO #link VALUES ('5', '150', 'BT', '100')
INSERT INTO #link VALUES ('6', '150', 'RT', '120')

INSERT INTO #categorylink VALUES ('S01', '100')
INSERT INTO #categorylink VALUES ('S02', '100')
INSERT INTO #categorylink VALUES ('B04', '150')

SELECT
       CASE
       WHEN #term.enscope IS NULL AND refterm.en IS NULL AND #categorylink.code IS NULL
       THEN #term.en
       ELSE NULL
       END,
       CHAR(9) + 'SN ' + #term.enscope,
       CHAR(9) + #link.reltype + CHAR(32) + refterm.en,
       CHAR(9) + 'CODE ' + #categorylink.code
    FROM #link
        INNER JOIN #term ON #term.termid = #link.termid
        INNER JOIN #term AS refterm ON refterm.termid = #link.refid
        LEFT JOIN #categorylink ON #term.termid = #categorylink.termid

    GROUP BY GROUPING SETS (#term.en, (#term.en, #term.enscope), (#term.en, #link.linkid, #link.reltype, refterm.en), (#term.en, #categorylink.code))
    ORDER BY #term.en, #categorylink.code, #link.linkid, #term.enscope
GO

DROP TABLE #term
DROP TABLE #link
DROP TABLE #categorylink
GO

Если в 'enscope' есть NULL, у меня есть повторяющаяся строка.

Если значение 'categorylink' отсутствует, у меня есть повторяющаяся строка.

Как избежать этого, пожалуйста?

Я хочу объединить их все в один столбец без дубликатов.

; WITH CTEterm AS (
    SELECT
       ROW_NUMBER() OVER (PARTITION BY #term.en, refterm.en ORDER BY #term.en) AS rownumber,
       #term.en AS mainterm,
       CHAR(9) + 'SN ' + #term.enscope AS scopenote,
       CHAR(9) + #link.reltype + CHAR(32) + refterm.en AS subterms,
       CHAR(9) + 'CODE ' + #categorylink.code AS codes
    FROM #link
       INNER JOIN #term ON #term.termid = #link.termid
       INNER JOIN #term AS refterm ON refterm.termid = #link.refid
       LEFT JOIN #categorylink ON #term.termid = #categorylink.termid
)

SELECT COALESCE(
    CASE
    WHEN rownumber = 1
    THEN mainterm
    ELSE NULL
    END,
    scopenote,
    subterms,
    codes
)
FROM CTEterm
GROUP BY GROUPING SETS ((mainterm, rownumber), (mainterm, scopenote), (mainterm, subterms), (mainterm, codes))
ORDER BY mainterm, codes, subterms, scopenote

GO

В основном, как избежать использования 'ELSE NULL' в CASE (например, 'else skip row')?

Это то, что я получаю, используя COALESCE

ABC
NULL
    SN abc_scopenote
    NT DEF
    NT GHI
    CODE S01
    CODE S02
NULL
DEF
    SN def_scopenote
    BT ABC
    RT GHI
NULL
GHI
    BT ABC
    RT DEF
    CODE B04

Это то, что мне нужно

ABC
    SN abc_scopenote
    NT DEF
    NT GHI
    CODE S01
    CODE S02
DEF
    SN def_scopenote
    BT ABC
    RT GHI
GHI
    BT ABC
    RT DEF
    CODE B04

Тот же вопрос здесь

1 Ответ

2 голосов
/ 18 июня 2011

Извините, если это не совсем то, что вы ожидали, но если вам просто нужно избавиться от NULL, то я не понимаю, почему вы не можете просто так:

;WITH CTEterm AS (
    SELECT
       ROW_NUMBER() OVER (PARTITION BY #term.en, refterm.en
                              ORDER BY #term.en) AS rownumber,
       #term.en AS mainterm,
       CHAR(9) + 'SN ' + #term.enscope AS scopenote,
       CHAR(9) + #link.reltype + CHAR(32) + refterm.en AS subterms,
       CHAR(9) + 'CODE ' + #categorylink.code AS codes
    FROM #link
       INNER JOIN #term ON #term.termid = #link.termid
       INNER JOIN #term AS refterm ON refterm.termid = #link.refid
       LEFT JOIN #categorylink ON #term.termid = #categorylink.termid
)
<b>SELECT
  AggValue
FROM (</b>
  SELECT
    <b>mainterm, codes, subterms, scopenote,</b>
    COALESCE(
      CASE WHEN rownumber = 1 THEN mainterm <s>ELSE NULL</s> END,
      scopenote,
      subterms,
      codes
    ) <b>AS AggValue</b>
  FROM CTEterm
  GROUP BY GROUPING SETS ((mainterm, rownumber), (mainterm, scopenote),
                          (mainterm, subterms), (mainterm, codes))
<b>) s
WHERE AggValue IS NOT NULL</b>
ORDER BY mainterm, codes, subterms, scopenote

Примечание: ELSE NULL удаляется здесь только потому, что оно ничего не меняет (NULL подразумевается, когда нет ELSE), а не потому, что вы получите что-то от его удаления.

...