SQL для MS Access: еще один вопрос о COUNT, JOIN, 0 и датах - PullRequest
0 голосов
/ 05 августа 2010

Я задал вопрос о вчерашних присоединениях . Однако, хотя это и отвечает на мой первоначальный вопрос, у меня больше проблем.

У меня есть телефонный стол

ID | Date | Grade
1 07/19/2010 Grade 1
2 07/19/2010 Grade 1
3 07/20/2010 Grade 1
4 07/20/2010 Grade 2
5 07/21/2010 Grade 3

У меня также есть таблица оценок

ID | Name
1 Grade 1
2 Grade 2
3 Grade 3
4 Grade 4
5 Grade 5
6 Grade 6
7 Grade 7
8 Grade 8
9 Grade 9
10 Grade 10
11 Grade 11
12 Grade 12

Я использую следующий запрос, чтобы получить СЧЕТ каждого класса в таблице телефонии, он прекрасно работает.

SELECT grade.ID, Count(telephony.Grade) AS Total
FROM grade LEFT JOIN telephony ON grade.ID=telephony.Grade
GROUP BY grade.ID
ORDER BY 1;

Это возвращает

ID | Total
1 3
2 1
3 1
4 0
5 0
6 0
7 0
8 0
9 0
10 0
11 0
12 0

Однако я пытаюсь сделать следующее:

Группировать по дате и возвращать результаты только между двумя датами

SELECT telephony.Date, grade.ID, Count(telephony.Grade) AS Total
FROM grade LEFT JOIN telephony ON grade.ID=telephony.Grade
WHERE telephony.Date BETWEEN #07/19/2010# AND #07/23/2010#
GROUP BY telephony.Date, grade.ID
ORDER BY 1;

Я получаю следующее

Date | ID | Total
07/19/2010 1 2
07/20/2010 1 1
07/20/2010 2 1
07/21/2010 3 1

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

Date | ID | Total
07/19/2010 1 2
07/19/2010 2 0
07/19/2010 3 0
07/19/2010 4 0
07/19/2010 5 0
07/19/2010 6 0
07/19/2010 7 0
07/19/2010 8 0
07/19/2010 9 0
07/19/2010 10 0
07/19/2010 11 0
07/19/2010 12 0
07/20/2010 1 1
07/20/2010 2 1
07/20/2010 3 0
07/20/2010 4 0
07/20/2010 5 0
07/20/2010 6 0
07/20/2010 7 0
07/20/2010 8 0
07/20/2010 9 0
07/20/2010 10 0
07/20/2010 11 0
07/20/2010 12 0
07/21/2010 1 2
07/21/2010 2 0
07/21/2010 3 1
07/21/2010 4 0
07/21/2010 5 0
07/21/2010 6 0
07/21/2010 7 0
07/21/2010 8 0
07/21/2010 9 0
07/21/2010 10 0
07/21/2010 11 0
07/21/2010 12 0
07/22/2010 1 2
07/22/2010 2 0
07/22/2010 3 0
07/22/2010 4 0
07/22/2010 5 0
07/22/2010 6 0
07/22/2010 7 0
07/22/2010 8 0
07/22/2010 9 0
07/22/2010 10 0
07/22/2010 11 0
07/22/2010 12 0
07/23/2010 1 2
07/23/2010 2 0
07/23/2010 3 0
07/23/2010 4 0
07/23/2010 5 0
07/23/2010 6 0
07/23/2010 7 0
07/23/2010 8 0
07/23/2010 9 0
07/23/2010 10 0
07/23/2010 11 0
07/23/2010 12 0

Я надеюсь, что кто-то может помочь. Я использую Microsoft Access 2003.

Приветствия

Ответы [ 4 ]

1 голос
/ 05 августа 2010

Создайте отдельный запрос по телефонии, который использует ваше ограничение BETWEEN #07/19/2010# AND #07/23/2010#.

qryTelephonyDateRange

SELECT *
FROM telephony
WHERE [Date] BETWEEN #07/19/2010# AND #07/23/2010#;

Затем в исходном запросе используйте:

LEFT JOIN qryTelephonyDateRange ON grade.ID=qryTelephonyDateRange.Grade

вместо

LEFT JOIN telephony ON grade.ID=telephony.Grade

Вы можете использовать подзапрос вместо отдельного именованного запроса для qryTelephonyDateRange.

Примечание Date - зарезервированное слово, поэтому я заключил в скобки имя, чтобы избежать неоднозначности ... Ядро базы данных Access поймет, что оно должно искать поле с именем Date вместо функции VBA Date (). Однако, если бы это был мой проект, я бы переименовал поле, чтобы избежать двусмысленности ... назовите его как-то вроде tDate.

Обновление : Вы просили увидеть подход подзапроса. Попробуйте это:

SELECT g.ID, t.[Date], Count(t.Grade) AS Total
FROM
    grade AS g
    LEFT JOIN (
        SELECT Grade, [Date]
        FROM telephony
        WHERE [Date] BETWEEN #07/19/2010# AND #07/23/2010#
        ) AS t
    ON g.ID=t.Grade
GROUP BY g.ID, t.[Date]
ORDER BY 1, 2;
0 голосов
/ 05 августа 2010

Я получил его на работу так:

  1. Создайте таблицу с именем Dates с одним полем даты / времени первичного ключа с именем MyDate (я с HansUp не использую зарезервированные слова, такие как «Date» для имен полей).
  2. Заполните таблицу требуемыми значениями даты (с 19.07.2010 по 23.07.2010, как в вашем примере).
  3. Напишите запрос со следующим оператором SQL

    ВЫБРАТЬ x.MyDate AS [Дата], x.ID, Количество (t.ID) AS Всего ОТ (ВЫБЕРИТЕ Даты.МояДата, Grade.ID ОТ ДАТЫ, ОБРАЗ) AS x ЛЕВНОЕ СОЕДИНЕНИЕ Телефония включена (x.MyDate = t.Date) и (x.ID = t.Grade) GROUP BY x.MyDate, x.ID;

Это должно получить результаты, которые вы просили.

Оператор подзапроса в SQL создает перекрестное соединение для получения каждой комбинации даты в таблице дат и оценки в таблице оценок.

(SELECT Dates.MyDate, Grade.ID FROM Dates, Grade)  AS x

Как только вы это сделаете, это всего лишь внешнее соединение с таблицей телефонии, чтобы сделать все остальное.

0 голосов
/ 05 августа 2010

Это совершенно другое. Вы хотите, чтобы диапазон отдельных дат был объединен с вашей первой таблицей, и предложение Между ними не сделает этого за вас.

Я думаю, вам понадобится таблица со всеми желаемыми датами, например, с 01.01.2010 по 31.12.2010, или с любым диапазоном, который вам нужно поддерживать. Один столбец, 365 или сколько угодно строк с одним значением даты в каждом.

затем объедините эту таблицу с таблицами с датами и оценками и ограничьте ее диапазоном дат, затем выполните агрегацию для подсчета.

Делайте шаг за шагом, и вам будет легче разобраться.

0 голосов
/ 05 августа 2010

Попробуйте это:

SELECT grade.ID, Count(telephony.Grade) AS Total
FROM grade LEFT JOIN telephony ON grade.ID=telephony.Grade
GROUP BY grade.ID
HAVING COUNT(telephony.Grade) > 0
ORDER BY grade.ID;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...