2010-05-06 5 views
2

J'ai une campagne de table qui a envoyé les détails des mails de la campagne.comment écrire cette requête en utilisant des jointures?

campaign_table: campaign_id campaign_name flag 
         1   test1  1 
         2   test2  1 
         3   test3  0 

une autre activité de campagne qui contient des détails sur les activités de la campagne.

campaign_activity: campaign_id is_clicked is_opened 
          1    0   1   
          1    1   0   
          2    0   1 
          2    1   0 

Je veux obtenir toutes les campagnes avec la valeur du drapeau 3 et le nombre de colonnes is_clicked ayant une valeur 1 et le nombre de colonnes avec une valeur is_opened 1 en une seule requête.

ie. campaign_id campaign_name numberofclicks numberofopens 
      1   test1   1    1 
      2   test2   1    1 

Je l'ai fait à l'aide de sous-requête avec la requête:

select c.campaign_id,c.campaign_name, 
(SELECT count(campaign_id) from campaign_activity WHERE campaign_id=c.id AND is_clicked=1) as numberofclicks, 
(SELECT count(campaign_id) from campaign_activity WHERE campaign_id=c.id AND is_clicked=1) as numberofopens 
FROM 
campaign c 
WHERE c.flag=1 

Mais les gens disent que l'utilisation des sous-requêtes ne sont pas une bonne convention de codage et vous devez utiliser se joindre au lieu de sous-requêtes . Mais je ne sais pas comment obtenir le même résultat en utilisant join. J'ai consulté certains de mes collègues et ils disent qu'il n'est pas possible d'utiliser joindre dans cette situation. Est-il possible d'obtenir le même résultat en utilisant des jointures? Si oui, s'il vous plaît dites-moi comment.

+0

Il est généralement correct d'utiliser des sous-requêtes dans la clause where mais éviter de les utiliser comme des colonnes. –

Répondre

4

Cela devrait faire l'affaire. Remplacez INNER JOIN par LEFT OUTER JOIN si vous souhaitez inclure des campagnes qui n'ont aucune activité.

SELECT 
    c.Campaign_ID 
    , c.Campaign_Name 
    , SUM(CASE WHEN a.Is_Clicked = 1 THEN 1 ELSE 0 END) AS NumberOfClicks 
    , SUM(CASE WHEN a.Is_Opened = 1 THEN 1 ELSE 0 END) AS NumberOfOpens 
FROM 
    dbo.Campaign c 
INNER JOIN 
    dbo.Campaign_Activity a 
ON a.Campaign_ID = c.Campaign_ID 
GROUP BY 
    c.Campaign_ID 
    , c.Campaign_Name 
+0

'CASE WHEN a.Is_XXXX <> 0 THEN 1 ELSE 0 END' peut être une meilleure idée, toutes les valeurs non nulles retournent 1, zéro et retourne 0. –

+0

Nice; avec cette instruction 'case', vous pouvez également facilement modifier la' jointure interne 'en une' jointure externe gauche 'pour intercepter les campagnes qui n'ont pas d'entrées dans la table des activités. – tzaman

+0

@Salman: Techniquement, l'OP a demandé spécifiquement des colonnes de comptage avec une valeur de 1, pas non nulle/nulle, donc c'est correct. – tzaman

0

Je suppose que cela devrait le faire:

select * from campaign_table inner join campaign_activity on campaign_table.id = campaign_activity.id where campaign_table.flag = 3 and campaign_activity.is_clicked = 1 and campaign_activity.is_opened = 1 

Attn: ce n'est pas testé dans une situation en direct

+0

Je veux obtenir le nombre de is_clicked et is_opened, ayant des valeurs 1. pas seulement les colonnes. – aquero

2

Hmm. Est ce que tu veux aussi simple que ça? Je ne suis pas sûr que je lis le droit de question ...

SELECT 
    campaign_table.campaign_id, SUM(is_clicked), SUM(is_opened) 
FROM 
    campaign_table 
    INNER JOIN campaign_activity ON campaign_table.campaign_id = campaign_activity.campaign_id 
WHERE 
    campaign_table.flag = 1 
GROUP BY 
    campaign_table.campaign_id 

Notez que avec un INNER JOIN ici, vous ne verrez pas les campagnes où il n'y a rien qui correspond à la table de campaign_activity. Dans ce cas, vous devez utiliser une LEFT JOIN et convertir NULL à 0 dans la SUM, par ex. SUM (IFNULL (is_clicked, 0)).

4

En supposant is_clicked et is_opened ne sont jamais 1 ou 0, cela devrait fonctionner:

select c.campaign_id, c.campaign_name, sum(d.is_clicked), sum(d.is_opened) 
from campaign c inner join campaign_activity d 
on c.campaign_id = d.campaign_id 
where c.flag = 1 
group by c.campaign_id, c.campaign_name 

Aucun sous-requêtes.

+1

Et si 'is_clicked' et' is_opened' ne sont pas seulement 1 ou 0, vous pouvez utiliser 'SUM (IF (is_clicked = 1,1,0))' –

+0

@Draco: Nice tweak! – tzaman

+0

Vous pouvez utiliser 'left join' pour récupérer même les campagnes qui n'ont pas d'activité correspondante; pour de telles lignes, les colonnes 'SUM' contiendront' NULL'. –

0

SQL dans sa forme la plus simple et la plus robuste est la suivante: (formaté pour la lisibilité)

SELECT 
campaign_table.campaign_ID, campaign_table.campaign_name, Sum(campaign_activity.is_clicked) AS numberofclicks, Sum(campaign_activity.is_open) AS numberofopens 

FROM 
campaign_table INNER JOIN campaign_activity ON campaign_table.campaign_ID = campaign_activity.campaign_ID 

GROUP BY 
campaign_table.campaign_ID, campaign_table.campaign_name, campaign_table.flag 

HAVING 
campaign_table.flag=1; 
Questions connexes