¿Cómo conseguir un grupo donde el recuento es cero?

12

Intentaré hacer un gráfico a partir de los datos de mi base de datos del servidor SQL. Tendré todas las calles con el recuento de los usuarios que viven en esta calle, incluso el recuento es cero.

Para esto he intentado esta consulta:

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

Y me da esta salida:

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

El problema es que la 5ta calle, donde no vive ningún usuario, no aparece en el resultado. ¿Podría hacer esto con el servidor SQL? Aquí tienes un violín

Actualización: si lo hago right join, tengo este resultado:

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

Ver este violín.

H. Pauwelyn
fuente
44
Como nadie explicó por qué su consulta no devuelve el resultado esperado: como la función agregada ignora NULL, debe contar una columna de la tabla interna (que contó desde la tabla externa) que se sabe que se define como NOT NULL (para poder distinguir entre NULL dentro de los datos y NULL creado por la Unión externa). La forma más sencilla es contar la columna de Ingreso:COUNT(u.streetid)
dnoeth
Porque right joiny right outer joinson las mismas cosas. Agregué una explicación en mi respuesta según lo sugerido por @ jpmc26.
SqlWorldWide

Respuestas:

17

La razón por la que su consulta no funcionó como se esperaba:

La unión interna le ofrece la intersección de 2 tablas. En su caso, no había ninguna entrada 5th streeten su tabla de usuarios y es por eso que join no produjo ninguna entrada para eso.

La unión externa (derecha o izquierda) dará el resultado de la unión interna y, además, todos los registros no calificados de la tabla izquierda o derecha, según el tipo (izquierda o derecha) de unión externa.

En este caso, puse Street a la izquierda de la combinación y utilicé la combinación externa izquierda, ya que quería todas las calles (incluso el recuento es cero) en su conjunto de resultados.

Cambie su consulta de selección a esto.

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

Resultado ingrese la descripción de la imagen aquí

SqlWorldWide
fuente
1
Para mí, cambiar de count (*) a count (customer.id), similar a lo que se muestra arriba, marcó la diferencia crítica. Gracias :)
Zeek
9

Esta es una forma posible.

select s.name as streets,
       (select count(*)
        from   users
        where  StreetID = s.id) cnt
from   streets s;
McNets
fuente
3
Seleccionar la misma tabla nuevamente en la cláusula select, ¿eso causa algún problema de rendimiento? (+1)
Saqib el
7

Limpiando el código para trabajar en una instancia sensible a mayúsculas y minúsculas ...

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 );

Cuando se usa COUNTcon un nombre de columna, cuenta los NOT NULLvalores.

Estoy usando un RIGHT JOINaquí para apaciguar a 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

Resultados:

street      count
1st street  2
2nd street  5
3rd street  2
4th street  1
5th street  0
Erik Darling
fuente
0
  1. Obtenga el recuento por ID de calle
  2. unirse a la identificación de la calle con la identificación de las calles
  3. Use Coalsesce ya que el valor nulo resultará

Aquí está la breve consulta:

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
Rakesh
fuente
Eso es con la unión izquierda
rakesh