Я пишу аналитический запрос в таблице журнала действий пользователя в Postgres 9.3. Он имеет дату регистрации, поле данных (которое можно суммировать) и тип пользователя. Я построил некоторые примеры данных/sql для этой проблемы, и я надеюсь получить помощь в выяснении последней части. SQL, необходимый для тестирования, ниже - он будет падать/создавать таблицу, называемую фактами, поэтому обязательно работайте в изолированной программной среде.Как получить все даты в последовательности для группы по запросу?
Я суммирую данные по неделям и типу пользователя - так что вы получаете подсчет поля данных для каждого типа пользователя каждую неделю. Проблема в том, что я получаю результаты, которые не хватает на неделю для пользователя type = 'x'. Поскольку на странице 9-9-13 нет пользовательских данных для типа пользователя «x», не появляется строка (см. Примеры результатов ниже). Я бы хотел, чтобы там была строка для этого типа пользователя и недели. Я хотел бы выполнить это, если возможно, с помощью одного оператора select, без таблиц temp или измерений (это связано с тем, что я передам этот sql-менеджер бизнес-менеджеру, и один автономный SQL-запрос выбора, скорее всего, станет более глупым (.! критика этого подхода приветствуется, но не ответ) Спасибо всем за любую помощь
Вот результаты, которые я получаю:
Sum test_week user_type 4 "2013-09-02" "x" 5 "2013-09-02" "y" 10 "2013-09-09" "y" 2 "2013-09-16" "x" 1 "2013-09-16" "y"
Вот результаты, которые я хочу:
Sum test_week user_type 4 "2013-09-02" "x" 5 "2013-09-02" "y" 0 "2013-09-09" "x" 10 "2013-09-09" "y" 2 "2013-09-16" "x" 1 "2013-09-16" "y"
Здесь это тестовые данные и оператор выбора SQL:
drop table if exists facts;
create temp table facts (signup_date date, data integer, record_type varchar, alt varchar);
insert into facts (signup_date, data, record_type) values
('9/3/2013',1,'x'),
('9/4/2013',1,'y'),
('9/5/2013',2,'x'),
('9/6/2013',3,'y'),
('9/7/2013',1,'x'),
('9/8/2013',1,'y'),
-- note the week of 9/9 to 9/16 has no 'x' records
('9/9/2013',2,'y'),
('9/10/2013', 3, 'y'),
('9/11/2013', 4, 'y'),
('9/12/2013', 1, 'y'),
('9/17/2013', 2, 'x'),
('9/18/2013', 1, 'y');
select coalesce(data, 0), test_week, record_type
from
(select sum(data) as data, record_type, to_timestamp(EXTRACT(YEAR FROM signup_date) || ' ' || EXTRACT(WEEK FROM signup_date),'IYYY IW')::date as test_week
from facts
group by record_type, test_week
) as facts
order by test_week, record_type
Спасибо! Ваш ответ имеет смысл использовать правое внешнее соединение с внутренним перекрестным объединением в качестве «виртуальной» таблицы размеров, чтобы принудительно использовать все комбинации строк * record_type независимо от исходных данных. Я принимаю ваш ответ в качестве правильного ответа. B/c SQL Gordon Linoff немного сложнее читать с использованием левого внешнего соединения, где таблица измерений является основной таблицей, а таблица фактов - объединенной таблицей. Я думаю, что ваша система с правильным внешним соединением легче понять. Думаю, оба ответа эквивалентны. –
@Steve Да, они эквивалентны. В моем ответе есть еще одна деталь, которая заключается в использовании 'date_trunc', который проще в использовании, чем конкатенация' extract'. Также применяется только к окончательному набору. –
Да, я заметил эти улучшения. Они - хорошая причина, почему ваше решение лучше, чем то, которое я разработал. Положив сумму на самый внешний запрос, вы избегаете уродства моего внутреннего креста (ответ ниже). Хороший SQL и еще раз спасибо! –