Как очистить эти данные Sql? - PullRequest
1 голос
/ 15 мая 2009

это ответ на вопрос к ранее заданному вопросу .

У меня есть следующие данные в одной таблице БД.

Name                LeftId    RightId
------------------------------------------
Cat                     1  
Cat                     1
Dog                     2
Dog                     2
Dog                               3
Dog                               3
Gerbil                  4         5 
Cat                
Bird
Cow                     6
Cow
Cow                               7
Dog                     8         9

Обратите внимание, что в некоторых строках нет данных для LeftId и RightId.

Теперь я хочу найти два разных запроса

  1. Все строки, у которых есть хотя бы 1 Id в одном из двух столбцов И строка без данных в обоих из этих двух столбцов Id.

например.

Cat     1
Cow     6 (or 7 .. i'm not worried)
  1. Все строки, где LeftId и RightId имеют значение NULL, сгруппированы под одним и тем же именем. Если другая строка (с тем же именем) имеет значение в LeftId или RightId, это имя не будет возвращено.

например.

Bird

хмм ..

РЕДАКТИРОВАТЬ: правильно переписал первый вопрос.

Ответы [ 5 ]

2 голосов
/ 18 мая 2009

Для первого запроса вы хотите строки, которые отвечают обоим из следующих критериев:

  1. Name в строке появляется в таблице в той же строке, в которой LeftId и RightId равны NULL.
  2. Name в строке появляется в таблице в той же строке, где хотя бы один из LeftId и RightId равен , а не NULL.

Ну, # 1 делается:

SELECT Name FROM Tbl WHERE (LeftId IS NULL) AND (RightId IS NULL)

И № 2 выполняется:

SELECT Name FROM Tbl WHERE (LeftId IS NOT NULL) OR (RightId IS NOT NULL)

Вы можете пересечь их , чтобы увидеть, какие Name появятся в обоих списках:

SELECT Name FROM Tbl WHERE (LeftId IS NULL) AND (RightId IS NULL)
INTERSECT
SELECT Name FROM Tbl WHERE (LeftId IS NOT NULL) OR (RightId IS NOT NULL)

Что возвращает:

Name
----
Cat
Cow

Но вам нужны LeftId и RightId, и вам все равно, какие, поэтому, я думаю, мы сгруппируемся по Имени:

SELECT Name, MIN(LeftId) AS LeftId, MIN(RightId) AS RightId 
    FROM Tbl WHERE Tbl.Name IN (
      SELECT Name FROM Tbl WHERE (LeftId IS NULL) AND (RightId IS NULL)
      INTERSECT
      SELECT Name FROM Tbl WHERE (LeftId IS NOT NULL) OR (RightId IS NOT NULL)
    )
GROUP BY Name

Который возвращает

Name  LeftId  RightId
----  ------  -------
Cat   1
Cow   6       7

lc уже предложил использовать COALESE, чтобы превратить эти два идентификатора в один. Так как насчет этого:

SELECT Name, COALESCE(MIN(LeftId),MIN(RightId)) AS Id 
    FROM Tbl WHERE Tbl.Name IN (
      SELECT Name FROM Tbl WHERE (LeftId IS NULL) AND (RightId IS NULL)
      INTERSECT
      SELECT Name FROM Tbl WHERE (LeftId IS NOT NULL) OR (RightId IS NOT NULL)
    )
GROUP BY Name

Что возвращает:

Name  Id
----  --
Cat   1
Cow   6

Для второго запроса вы хотите строки, которые соответствуют следующим критериям:

  1. Name появляется только в строках, которые не имеют LeftId и RightId

Я не могу придумать, как выполнить такой запрос в SQL с помощью самоссылки в одном наборе критериев, поэтому я разбью его на два критерия. Оба должны быть выполнены, чтобы быть приемлемыми:

  1. Name появляется в строках, которые не имеют LeftId и RightId
  2. Name действительно не появляются в строках, которые имеют LeftId или RightId

Выполнение # 1 просто:

SELECT Name FROM Tbl WHERE (LeftId IS NULL) AND (RightId IS NULL)

Но № 2 сложно. Конечно, выполнение противоположного # 2 («все Name, которые появляются в строках с LeftId или RightId) такое же, как и раньше:

SELECT Name FROM Tbl WHERE (LeftId IS NOT NULL) OR (RightId IS NOT NULL)

Теперь наступает хитрый момент - мы хотим, чтобы все строки подчинялись # 1, но не подчинялись противоположности # 2. Вот где полезно EXCEPT :

SELECT Name FROM Tbl WHERE (LeftId IS NULL) AND (RightId IS NULL)
EXCEPT
SELECT Name FROM Tbl WHERE (LeftId IS NOT NULL) OR (RightId IS NOT NULL)

Что возвращает:

Name
----
Bird

Что мы и хотели!

0 голосов
/ 15 мая 2009

Запрос 1:

SELECT [Name], [LeftID], [RightID]

FROM [TestTable]

WHERE -- "All rows which have at least 1 Id in one of the two columns"
      ([LeftID] IS NOT NULL OR [RightID] IS NOT NULL)
      OR
      -- "Rows with NO data in both of those two Id columns"
      ([LeftID] IS NULL AND [RightID] IS NULL)

Запрос 2:

SELECT [Name], [LeftID], [RightID]

FROM [TestTable]

WHERE -- "All the rows where LeftId and RightId are NULL
      -- grouped by the same name"
      ([LeftID] IS NULL AND [RightID] IS NULL)
      AND
      -- "If another row (with the same name) has a value
      -- in the LeftId or RightId, this name will not be returned"    
      ([Name] NOT IN (SELECT DISTINCT [Name] FROM [TestTable]
                      WHERE [LeftID] IS NOT NULL
                            OR
                            [RightID] IS NOT NULL))

GROUP BY [Name], [LeftID], [RightID]

Результаты:

Name                                               LeftID      RightID
-------------------------------------------------- ----------- -----------
Cat                                                1           NULL
Cat                                                1           NULL
Dog                                                2           NULL
Dog                                                2           NULL
Dog                                                NULL        3
Dog                                                NULL        3
Gerbil                                             4           5
Cat                                                NULL        NULL
Bird                                               NULL        NULL
Cow                                                6           NULL
Cow                                                NULL        NULL
Cow                                                NULL        7
Dog                                                8           9

(13 row(s) affected)

Name                                               LeftID      RightID
-------------------------------------------------- ----------- -----------
Bird                                               NULL        NULL

(1 row(s) affected)
0 голосов
/ 15 мая 2009

Запрос 1)

SELECT * 
FROM Table 
WHERE (LeftID IS NULL AND RightID IS NOT NULL) 
    OR (LeftID IS NOT NULL AND RightID IS NULL)

Запрос 2)

SELECT * 
FROM Table 
WHERE LeftID IS NULL AND RightID IS NULL
0 голосов
/ 15 мая 2009

Надеюсь, я вас правильно понял.

Запрос 1:

SELECT t1.Name, COALESCE(MIN(t1.LeftID), MIN(t1.RightID))
FROM Table t1
WHERE EXISTS(SELECT t2.Name
             FROM Table t2
             WHERE t2.Name = t1.Name 
             AND   t2.LeftID IS NULL AND t2.RightID IS NULL)
AND   COALESCE(MIN(t1.LeftID), MIN(t1.RightID)) IS NOT NULL
GROUP BY t1.Name

Запрос 2:

SELECT t1.Name
FROM Table t1
WHERE NOT EXISTS(SELECT t2.Name
                 FROM Table t2
                 WHERE t2.Name = t1.Name
                 AND   (t2.LeftID IS NOT NULL OR t2.RightID IS NOT NULL))
0 голосов
/ 15 мая 2009

Если я вас правильно понимаю, то это довольно тривиально:

1

SELECT * 
FROM your_table 
WHERE (LeftId IS NOT NULL 
AND RightId IS NULL)
OR
(LeftId IS NULL 
AND RightId IS NOT NULL)

2

SELECT * 
FROM your_table
WHERE 
    NOT EXISTS 
              (SELECT * FROM your_table y1
               WHERE (y1.LeftId IS NOT NULL OR y1.RightId IS NOT NULL)
               AND y1.name = your_table.name)

Если это не правильно, возможно, вы могли бы уточнить.

Редактировать: обновлено

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...