SQL, соединяющий две таблицы на основе даты

#sql #sql-server

Вопрос:

Вот моя ситуация: у меня есть 2 таблицы, таблицы вопросов и ответов, обе из которых содержат столбец post_date. Я хочу получить количество вопросов и ответов за последние 7 дней, независимо от того, равно ли количество 0. Обратитесь к этому для получения желаемого результата

Я попробовал следующий код:

 SELECT CONVERT(varchar, DATEADD(DAY,0, DATEDIFF(day,0, post_date)),23) AS q_date, COUNT(id) AS q_count
FROM [Question]
WHERE post_date >= DATEADD(day,-7, GETDATE())
GROUP BY DATEADD(DAY,0, DATEDIFF(day,0, post_date))
UNION
SELECT CONVERT(varchar, DATEADD(DAY,0, DATEDIFF(day,0, post_date)),23)AS a_date, COUNT(id) AS a_count
FROM [Answer]
WHERE post_date >= DATEADD(day,-7, GETDATE())
GROUP BY DATEADD(DAY,0, DATEDIFF(day,0, post_date))
 

Но в итоге количество вопросов и ответов сливается в одну колонку. Кроме того, результат отображается не для каждого дня, а только для дней, в которых существует счетчик. Выходные данные показаны, как показано ниже:

   q_date     q_count
----------   -------
2021-06-11      1
2021-06-12      1
2021-06-13      1
2021-06-13      2
2021-06-14      1
 

Любые предложения будут высоко оценены!


Решение

Решение, предложенное @Gordon, отлично подходит для этого результата:

    date      q_count     a_count
----------   -------     -------
2021-06-11      1           0
2021-06-12      0           1
2021-06-13      2           1
2021-06-14      0           1
 

Для отображения за все 7 дней, даже если в течение нескольких дней данных нет, это способ:

 ;WITH DateTable
AS
(
    SELECT DATEADD(day,-6, CONVERT(date, GETDATE())) AS [DATE]
    UNION ALL
    SELECT DATEADD(dd, 1, [DATE])
    FROM DateTable
    WHERE DATEADD(dd, 1, [DATE]) <= CONVERT(date, GETDATE())
)
SELECT COALESCE(ques.date, ans.date) as date,
   COALESCE(ques.q_count, 0) as q_count,
   COALESCE(ans.a_count, 0) as a_count
FROM 
    (SELECT dt.[DATE], COUNT(q.id) as [Q_COUNT]
    FROM [DateTable] dt
    LEFT JOIN [Question] q
    ON dt.[DATE] = CONVERT(date, q.post_date)
    GROUP BY dt.[DATE]) ques
FULL JOIN
    (SELECT dt.[DATE], COUNT(a.id) as [A_COUNT]
    FROM [DateTable] dt
    LEFT JOIN [Answer] a
    ON dt.[DATE] = CONVERT(date, a.post_date)
    GROUP BY dt.[DATE]) ans
ON ques.DATE = ans.DATE
 

Выход:

    date      q_count     a_count
----------   -------     -------
2021-06-10      0           0
2021-06-11      1           0
2021-06-12      0           1
2021-06-13      2           1
2021-06-14      0           1
2021-06-15      0           0
2021-06-16      0           0
 

Наконец, большое СПАСИБО @Gordon за то, что развеял мои сомнения!

Ответ №1:

Использовать JOIN , FULL JOIN на самом деле:

 SELECT COALESCE(q.date, a.date),
       COALESCE(q.q_count, 0) as q_count,
       COALESCE(a.a_count, 0) a a_count
FROM (SELECT CONVERT(date, post_date) as date, COUNT(id) AS q_count
      FROM [Question]
      WHERE post_date >= DATEADD(day, -7, CONVERT(date, GETDATE()))
      GROUP BY ONVERT(date, post_date)
     ) q FULL JOIN
     (SELECT CONVERT(date, post_date) as date, COUNT(id) AS a_count
      FROM [Answer]
      WHERE post_date >= DATEADD(day, -7, CONVERT(date, GETDATE()))
      GROUP BY CONVERT(date, post_date)
     ) a
     ON a.date = q.date;
 

В вашем коде есть пара проблем:

  • Вы можете просто преобразовать дату/время в a date , чтобы удалить компонент времени. Гораздо лучший подход, чем преобразование в строку.
  • GETDATE() имеет временную составляющую, поэтому сравнение с GETDATE() не делает того, что вы (вероятно) намереваетесь).

Комментарии:

1. Привет, спасибо за ваш ответ! Он показывает только даты, в которых число q и число a не равны 0. Как, если я хочу отобразить дату, даже если оба счетчика равны 0?

2. @lsx . . . Это с помощью full join . Он должен показывать строки, в которых либо нет 0 .