Как я могу получить данные из двух разных таблиц, связать их с данными из третьей таблицы и получить все в одном отчете?

#sql #database #oracle

#sql #База данных #Oracle

Вопрос:

Здесь у меня небольшая проблема. У меня есть две разные таблицы, в одной из которых хранится количество показов конкретного баннера на веб-сайте за день и на пользователя, а в другой — количество электронных писем, отправленных любому пользователю за любую заданную дату.

Примерно так:

Баннеры

ДАТА ПОКАЗОВ ИДЕНТИФИКАТОРА ПОЛЬЗОВАТЕЛЯ ИДЕНТИФИКАТОРА КЛИЕНТА ИДЕНТИФИКАТОРА БАННЕРА
________ _______ _________ ________ ___________
05.04.11 AX745 CC CC45 4 
05.04.11 AX745 KC KC66 1 
07.04.11 XY555 DP DP45 2

И:

ЭЛЕКТРОННЫЕ ПИСЬМА

ДАТА USER_ID ИДЕНТИФИКАТОР электронной ПОЧТЫ CLIENT_ID
________ _______ ________ _________
05.04.11 AX745 EM001 CC 
05.04.11 AX745 EM005 BK
07.04.11 XY555 EM008 DP

Обе таблицы содержат идентификатор клиента и некоторую информацию о дате, помимо идентификатора пользователя.

Мне также нужно сослаться на идентификатор клиента, чтобы получить фактическое имя клиента, и они хранятся еще в третьей таблице, вот так:

КЛИЕНТЫ

CLIENT_ID КЛИЕНТ
_________ ________________________
CC COCA-COLA
KC KFC
DP DOMINOS
BK BURGER KING

Мне нужен запрос, который будет возвращать по каждой дате для каждого списка пользователей, сколько показов у пользователя было каждого баннера, а также какому клиенту он принадлежит, и сколько электронных писем пользователь отправил в этот конкретный день и от какого клиента.

Что-то примерно такое:

ДАТА USER_ID BANNER_CLIENT_ID BANNER_ID ПОКАЗЫ EMAIL_ID EMAIL_CLIENT_ID
________ _______ ________________ _________ ___________ ________ _______________
05.04.11 AX745 COCA-COLA CC45 4 EM001 COCA-COLA
05.04.11 AX745 EM005 BURGER-KING
05.04.11 AX745 KFC KC66 1 
07.04.11 XY555 DOMINOS DP45 2 EM008 DOMINOS

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

Буду признателен за любую помощь.

Спасибо!

C

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

1. Вы должны включить названия таблиц!

2. Извините за это, вы абсолютно правы. Я добавил несколько имен и поле, которое я забыл во второй таблице.

Ответ №1:

Приведенный ниже запрос должен выдать желаемый результат.

 SELECT A.DATE, A.USER_ID, A.BANNER_ID, A.IMPRESSIONS, B.EMAIL_ID, C.CLIENT AS EMAIL_CLIENT_ID
FROM BANNERS A
LEFT JOIN EMAILS B ON A.CLIENT_ID=B.CLIENT_ID
LEFT JOIN CLIENTS C ON A.CLIENT_ID=C.CLIENT_ID
WHERE A.DATE=TO_DATE('04/07/11', 'MM-DD-YY')
  

Ответ №2:

 Declare @impressions table
( [DATE]        date,
  [USER_ID]     varchar(10),
  [CLIENT_ID]   varchar(10),
  [BANNER_ID]   varchar(10),
  [IMPRESSIONS] int
)

Declare @ClientEmails table
( [DATE]        date,
  [USER_ID]     varchar(10),
  [EMAIL_ID]    varchar(10),
  [CLIENT_ID]   varchar(10)
)

Declare @Clients table
(  [CLIENT_ID]   varchar(10),
   [CLIENT]      varchar(50)
)   


Insert Into  @impressions ([DATE], [USER_ID], [CLIENT_ID], [BANNER_ID], [IMPRESSIONS])
Values ('2011/04/05', 'AX745', 'CC', 'CC45', 4),
       ('2011/04/05', 'AX745', 'KC', 'KC66', 1),
       ('2011/04/07', 'XY555', 'DP', 'DP45', 2)


Insert Into  @ClientEmails ([DATE],[USER_ID],[EMAIL_ID], [CLIENT_ID])
Values ('2011/04/05', 'AX745', 'EM001', 'CC'),
       ('2011/04/05', 'AX745', 'EM005', 'BK'),
       ('2011/04/07', 'XY555', 'EM008', 'DP')

Insert Into  @Clients([CLIENT_ID], [CLIENT])
Values ('CC', 'COCA-COLA'),
       ('KC', 'KFC'),
       ('DP', 'DOMINOS'),
       ('BK', 'BURGER KING')


Select isNull(imp.[DATE], eml.[DATE]) as [DATE],
       imp.[USER_ID],
       cli.[CLIENT] as [BANNER_CLIENT_ID],
       imp.[USER_ID] as [BANNER_ID],
       imp.[IMPRESSIONS],
       eml.[EMAIL_ID],
       emc.[CLIENT]  as [EMAIL_CLIENT_ID]
  from @impressions imp
  Left Join @Clients cli 
    on imp.[CLIENT_ID]=cli.[CLIENT_ID]
  Full outer Join @ClientEmails eml 
    on imp.[CLIENT_ID]=eml.[CLIENT_ID] 
   and imp.[USER_ID]=eml.[USER_ID]
   and imp.[DATE]=eml.[DATE]
  Left Join @Clients emc 
    on eml.CLIENT_ID=emc.CLIENT_ID  
 Order By [DATE]
  

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

1. Просто используйте правильные имена таблиц вместо табличных переменных (синтаксис SQL server)

Ответ №3:

Поскольку у вас могут быть либо баннеры без электронных писем, либо электронные письма без БАННЕРОВ, вам потребуется использовать ПОЛНОЕ ВНЕШНЕЕ СОЕДИНЕНИЕ.

 SELECT 
  nvl(A.DATE, b.date) as DATE,
  nvl(A.USER_ID, b.user_id) as USER_ID,
  c.client as banner_client_id,
  A.BANNER_ID, 
  A.IMPRESSIONS,  
  B.EMAIL_ID,  
  D.CLIENT AS EMAIL_CLIENT_ID
FROM 
  BANNERS A
  FULL OUTER JOIN EMAILS B ON (A.USER_ID=B.USER_ID AND 
                         a.DATE = b.DATE and
                         A.CLIENT_ID = B.CLIENT_ID)
  LEFT OUTER JOIN CLIENTS C ON (C.CLIENT_ID= a.CLIENT_ID)
  LEFT OUTER JOIN CLIENTS D ON (D.CLIENT_ID= B.CLIENT_ID)
  

Полная версия запроса, включая некоторые примеры данных, показана ниже:

 with banners as (
  select date '2011-04-05' as date_col, 'AX745' as user_id, 'CC' as client_id, 'CC45' as banner_id, 4 as impressions from dual union all
  select date '2011-04-05' as date_col, 'AX745' as user_id, 'KC' as client_id, 'KC56' as banner_id, 1 as impressions from dual union all
  select date '2011-04-07' as date_col, 'XY555' as user_id, 'DP' as client_id, 'CC45' as banner_id, 2 as impressions from dual
),
emails as (
  select date '2011-04-05' as date_col, 'AX745' as user_id, 'EM001' as email_id, 'CC' as client_id from dual union all
  select date '2011-04-05' as date_col, 'AX745' as user_id, 'EM005' as email_id, 'BK' as client_id from dual union all
  select date '2011-04-07' as date_col, 'XY555' as user_id, 'EM008' as email_id, 'DP' as client_id from dual
),
clients as (
  select 'CC' as client_id, 'Coca-Cola' as client_name from dual union all
  select 'KC' as client_id, 'KFC' as client_name from dual union all
  select 'DP' as client_id, 'Dominos' as client_name from dual union all
  select 'BK' as client_id, 'Burger King' as client_name from dual
)
select 
  nvl(A.DATE_col, b.date_col) as DATE_col,
  nvl(A.USER_ID, b.user_id) as USER_ID,
  c.client_name as banner_client_id,
  A.BANNER_ID, 
  A.IMPRESSIONS,  
  B.EMAIL_ID,  
  D.CLIENT_name AS EMAIL_CLIENT_ID
from 
  banners a
  full outer join emails b on (A.USER_ID=B.USER_ID AND 
                         a.DATE_col = b.DATE_col and
                         A.CLIENT_ID = B.CLIENT_ID)
  left outer join clients c on (a.client_id = c.client_id)
  left outer join clients d on (b.client_id = d.client_id)
  

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

1. Спасибо за это. Это может быть ключом. Краткий вопрос: что это за команда nvl? Я не знаком с этим (но опять же, я только недавно начал работать с SQL).

2. @Carlos_Blive Это функция Oracle. Если первый параметр равен null, то функция возвращает второй параметр, в противном случае она возвращает первый параметр. Подробности здесь: download.oracle.com/docs/cd/B19306_01/server.102/b14200/… Если вы не работаете с Oracle, тогда применяются другие вещи, такие как NULLIF или IsNull или что-то в этом роде.

3. Я думаю, что это на правильном пути, но, похоже, я не могу заставить это работать. Компонент электронной почты отображается пустым, хотя я знаю, что там есть данные. Если я запускаю для этого отдельный отчет, все получается нормально. Я подозреваю, что это может быть как-то связано с датами? В одной таблице это отображается как «дд / мм / гггг», а в другой — как «дд / мм / гггг чч: мм: сс». Может ли это быть причиной?

4. Хммм, интересно. Если вы не получаете электронные письма, то это может быть потому, что вы используете LEFT OUTER JOIN вместо FULL OUTER JOIN . Вы можете прочитать больше о различиях здесь: download.oracle.com/docs/cd/B28359_01/server.111/b28286/… Проблема может заключаться в датах. Вы могли бы использовать trunc(a.date_col) = b.date_col с транком на соответствующей стороне (стороне со временем), но это, вероятно, приведет к дублированию данных.