Оператор SQL для включения строк, которые не имеют совпадений в коррелированном подзапросе - PullRequest
1 голос
/ 14 сентября 2009

У меня есть коррелированный подзапрос ниже. Каждый идентификатор (147, 148, 149) в таблице 1 имеет много записей в таблице 2. У идентификатора 148, однако, нет записей, соответствующих условию времени в выражении. Поэтому он не включен в вывод. Я хочу, чтобы он был включен с 0 для столбца подсчета. Что нужно изменить?

SELECT b.fkid, COUNT(DISTINCT username)
FROM table2 AS b
WHERE
b.fkid IN ( 147,148,149 )
AND time > (SELECT SUBTIME(a.endTime, SEC_TO_TIME( 60*60 )) FROM table1 AS a WHERE a.id = b.fkid)
GROUP BY b.fkid

Это утверждение возвращает:

b.fkid   COUNT(DISTINCT username)
147      41
149      26

Я хочу вернуть:

b.fkid   COUNT(DISTINCT username)
147      41
148       0
149      26

Хорошо, я получил решение. Это модифицированная версия ответа rexem:

SELECT t.fkid,
   IFNULL(nu.num_users, 0)
FROM TABLE_2 t
LEFT JOIN (SELECT t.fkid,
                  COUNT(DISTINCT t.username) 'num_users'
           FROM TABLE_2 t
           JOIN TABLE_1 a ON a.id = t.fkid
                          AND SUBTIME(a.endTime, SEC_TO_TIME( 60*60 )) < t.time
           GROUP BY t.fkid) nu ON nu.fkid = t.fkid
WHERE t.fkid IN (147, 148, 149)
GROUP BY t.fkid, nu.num_users

Changes from rexem's answer:
"SEC_TO_TIME( 60*60 )) = t.time" to "SEC_TO_TIME( 60*60 )) < t.time"
Removed "t.time" in GROUP BY clause of subquery

Ответы [ 4 ]

1 голос
/ 14 сентября 2009

Попробуйте:

   SELECT t.fkid,
          IFNULL(nu.num_users, 0)
     FROM TABLE_2 t
LEFT JOIN (SELECT t.fkid,
                  COUNT(DISTINCT t.username) 'num_users'
             FROM TABLE_2 t
             JOIN TABLE_1 a ON a.id = t.fkid
                           AND SUBTIME(a.endTime, SEC_TO_TIME( 60*60 )) = t.time
         GROUP BY t.fkid) nu ON nu.fkid = t.fkid
   WHERE t.fkid IN (147, 148, 149)
GROUP BY t.fkid, nu.num_users
1 голос
/ 14 сентября 2009

Попробуйте использовать COALESCE для обработки сценариев, в которых время сравнивается с пустым набором (например, потому что нет совпадений между таблицей1 и таблицей2):

SELECT b.fkid, COUNT(DISTINCT username)
FROM table2 AS b
WHEREb.fkid IN ( 147,148,149 )
AND time > COALESCE((SELECT SUBTIME(a.endTime, SEC_TO_TIME( 60*60 )) FROM table1 AS a WHERE a.id = b.fkid), 0)
GROUP BY b.fkid

COALESCE принимает неограниченный набор параметров и из этой группы возвращает первый ненулевой параметр.

0 голосов
/ 14 сентября 2009

Я думаю, что ваш лучший шанс получить ноль в результате - использовать (непересекающийся) UNION. Первая часть будет вашим текущим запросом; второе предложение будет искать значения, в которых нет соответствующих записей, выбирая константу 0 для столбца count.

Часто внешнее соединение может помочь. Сложность заключается в том, что внешнее объединение будет производить строку данных для ID = 148, и поэтому COUNT даст ответ 1, а не 0.

0 голосов
/ 14 сентября 2009
SELECT a.ID, COUNT(DISTINCT username)
FROM table1 AS a LEFT JOIN table2 AS b
on a.ID = b.fkID
WHERE a.ID IN ( 147,148,149 )
AND b.time > SUBTIME(a.endTime, SEC_TO_TIME( 60*60 )) 
GROUP BY a.ID

Помогает ли это в любом случае?

РЕДАКТИРОВАТЬ: я не уверен, может ли это работать в MySQL. Но я надеюсь, что у вас есть идея построить запрос, используя это.

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