Comment obtenir un groupe dont le nombre est nul?


12

Je vais essayer de faire un graphique à partir des données de ma base de données SQL Server. J'aurai toutes les rues avec le nombre d'utilisateurs qui vivent dans cette rue, même le nombre est nul.

Pour cela, j'ai essayé cette requête:

Create table Streets(
  ID int IDENTITY  primary key,
  Name varchar(100)
);

create table users(
  ID int IDENTITY  primary key,
  Username varchar(100),
  StreetID int references Streets(id)
);

insert into streets values ('1st street'), ('2nd street'), ('3rd street'), 
                           ('4th street'), ('5th street');
insert into users values ('Pol', 1), ('Doortje', 1), ('Marc', 2), ('Bieke', 2), 
                         ('Paulien', 2), ('Fernand', 2), ('Pascal', 2), ('Boma', 3), 
                         ('Goedele', 3), ('Xavier', 4);

select s.name as street, count(s.name) as count 
from users u inner join streets s on u.streetid = s.id
group by s.name

Et ça me donne cette sortie:

|   | street     | count |
| - | ---------- | ----- |
| 1 | 1st street | 2     |
| 2 | 2nd street | 5     |
| 3 | 3rd street | 2     |
| 4 | 4th street | 1     |

Le problème est que la 5ème rue, où aucun utilisateur ne vit, n'apparaît pas sur le résultat. Puis-je faire cela avec SQL Server? Ici tu as un violon

Mise à jour: si je le fais right join, j'ai ce résultat:

|   | street     | count |
| - | ---------- | ----- |
| 1 | 1st street | 2     |
| 2 | 2nd street | 5     |
| 3 | 3rd street | 2     |
| 4 | 4th street | 1     |
| 5 | 5th street | 1     | 

Voir ce violon.


4
Comme personne n'a expliqué pourquoi votre requête ne retourne pas le résultat attendu: Comme la fonction d'agrégation ignore les NULL, vous devez compter une colonne de la table interne (vous avez compté à partir de la table externe) qui est connue pour être définie comme NOT NULL (pour pouvoir faire la distinction entre les valeurs NULL dans les données et les valeurs NULL créées par la jointure externe). Le moyen le plus simple est de compter la colonne de jointure:COUNT(u.streetid)
dnoeth

Parce que right joinet ce right outer joinsont les mêmes choses. J'ai ajouté une explication dans ma réponse comme suggéré par @ jpmc26.
SqlWorldWide

Réponses:


17

La raison pour laquelle votre requête n'a pas fonctionné comme prévu:

La jointure interne vous donne l'intersection de 2 tables. Dans votre cas, il n'y avait aucune entrée pour 5th streetdans votre table d'utilisateurs et c'est pourquoi join n'a produit aucune entrée pour cela.

La jointure externe (droite ou gauche) donnera le résultat de la jointure interne et en plus tous les enregistrements non éligibles du tableau de gauche ou de droite selon le type (gauche ou droite) de jointure externe.

Dans ce cas, j'ai mis Street à gauche de la jointure et utilisé la jointure externe gauche comme vous vouliez toutes les rues (même le nombre est nul) dans votre jeu de résultats.

Remplacez votre requête de sélection par ceci.

SELECT S.Name AS Street,
       Count(U.Username) AS COUNT
FROM Streets S
LEFT OUTER JOIN Users U ON U.Streetid = S.Id
GROUP BY S.Name

Résultat entrez la description de l'image ici


1
Pour moi, passer du compte (*) au compte (customer.id) - similaire à celui illustré ci-dessus - a fait la différence critique. Merci :)
Zeek

9

C'est une façon possible.

select s.name as streets,
       (select count(*)
        from   users
        where  StreetID = s.id) cnt
from   streets s;

7

Nettoyage du code pour travailler sur une instance sensible à la casse ...

CREATE TABLE Streets
(
    ID INT IDENTITY PRIMARY KEY,
    Name VARCHAR(100)
);

CREATE TABLE users
(
    ID INT IDENTITY PRIMARY KEY,
    Username VARCHAR(100),
    StreetID INT
        REFERENCES Streets ( ID )
);

INSERT INTO Streets
VALUES ( '1st street' ),
    ( '2nd street' ),
    ( '3rd street' ),
    ( '4th street' ),
    ( '5th street' );
INSERT INTO users
VALUES ( 'Pol', 1 ),
    ( 'Doortje', 1 ),
    ( 'Marc', 2 ),
    ( 'Bieke', 2 ),
    ( 'Paulien', 2 ),
    ( 'Fernand', 2 ),
    ( 'Pascal', 2 ),
    ( 'Boma', 3 ),
    ( 'Goedele', 3 ),
    ( 'Xavier', 4 );

Lorsque vous utilisez COUNTun nom de colonne, il compte les NOT NULLvaleurs.

J'utilise un RIGHT JOINici pour apaiser Joe Obbish.

SELECT   s.Name AS street, COUNT(u.Username) AS count
FROM     users AS u
RIGHT JOIN Streets AS s
ON u.StreetID = s.ID
GROUP BY s.Name

Résultats:

street      count
1st street  2
2nd street  5
3rd street  2
4th street  1
5th street  0

0
  1. Obtenez le nombre par identifiant de rue
  2. rejoindre l'identifiant de la rue avec l'identifiant des rues
  3. Utilisez Coalsesce car la valeur nulle résultera

Voici la courte requête:

select Name, coalesce( u.ct,0)ct FROM streets s left join (
select StreetID,count(*)ct from users group by StreetID)u on s.ID=u.StreetID

C'est avec jointure gauche
rakesh
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.