53 messaggi dal 15 novembre 2004
Eseguo il conteggio di alcuni record in una vista che unisce due tabelle tramite la chiave primaria e li raggruppo per un valore:

Select Valore1, COUNT(Valore2) as NumeroRicorrenze
FROM view_Valori
GROUP BY Valore1

ottengo un recordset con due colonne, ad es:
PIPPO 3
PLUTO 2
PAPERINO 4

I valori con NumeroRicorrenze= 0 non appaiono, mentre io ne ho bisogno per disegnare la mia tabella in questo modo:
PIPPO 3
PLUTO 2
PAPERINO 4
ORAZIO 0

Ho provato a costruire la vista con i vari tipi di JOIN ma non ho ottenuto nulla di differente.

Un'idea?

Luciano
1.976 messaggi dal 27 luglio 2005
Contributi
salve
luciano.net ha scritto:
Eseguo il conteggio di alcuni record in una vista che unisce due tabelle tramite la chiave primaria e li raggruppo per un valore:

Select Valore1, COUNT(Valore2) as NumeroRicorrenze
FROM view_Valori
GROUP BY Valore1

ottengo un recordset con due colonne, ad es:
PIPPO 3
PLUTO 2
PAPERINO 4

I valori con NumeroRicorrenze= 0 non appaiono, mentre io ne ho bisogno per disegnare la mia tabella in questo modo:
PIPPO 3
PLUTO 2
PAPERINO 4
ORAZIO 0

Ho provato a costruire la vista con i vari tipi di JOIN ma non ho ottenuto nulla di differente.

Un'idea?

Luciano

la funzione di aggregazione COUNT() restituisce il numero di voci di un gruppo comprendendo ancue eventuali NULL, ma probabilmente il tuo problema deriva dalla mancanza di proiezione sull'intersezione della regola DRI...
ad ogni modo, modificando la natural join in una join esterna dovrebbe risolverti il problema..
SET NOCOUNT ON
CREATE TABLE dbo.masterT (
Id int NOT NULL PRIMARY KEY ,
Dati varchar(10)
)
CREATE TABLE dbo.detailT (
Id int NOT NULL PRIMARY KEY ,
IdRif int NOT NULL
CONSTRAINT fk_masterT_detailT
FOREIGN KEY
REFERENCES dbo.masterT (Id),
Dati varchar(10)
)
GO
INSERT INTO dbo.masterT VALUES ( 1 , 'Paperino' )
INSERT INTO dbo.masterT VALUES ( 2 , 'Topolino' )
INSERT INTO dbo.masterT VALUES ( 3 , 'vuoto' )

INSERT INTO dbo.detailT VALUES ( 1 , 1 , 'Paperino1' )
INSERT INTO dbo.detailT VALUES ( 2 , 1 , 'Paperino2' )
INSERT INTO dbo.detailT VALUES ( 3 , 1 , 'Paperino3' )

INSERT INTO dbo.detailT VALUES ( 4 , 2 , 'Topolino1' )
INSERT INTO dbo.detailT VALUES ( 5 , 2 , 'Topolino2' )

SELECT m.dati AS [Oggetto], COUNT(d.Id) AS [Ricorrenze]
FROM dbo.masterT m LEFT JOIN dbo.detailT d
ON m.Id = d.IdRif
GROUP BY m.Dati
GO
DROP TABLE dbo.detailT , dbo.masterT

come vedrai dal risultato, ti viene anche emesso un warning relativo a eventuali parziali eliminazioni delle proiezioni di NULL

Warning: Null value is eliminated by an aggregate or other SET operation.
,
informazione comunque eliminabile provvedendo l'impostazione
SET ANSI_WARNINGS OFF
, http://msdn.microsoft.com/library/default.asp?url=/library/en-us/tsqlref/ts_set-set_6d2r.asp
saluti

Andrea Montanari
http://www.hotelsole.com - http://www.hotelsole.com/asql/index.php
53 messaggi dal 15 novembre 2004
OK, così funziona.
Se però utilizzo un filtro non funziona più:

SELECT m.dati AS [Oggetto], COUNT(d.Id) AS [Ricorrenze]
FROM dbo.masterT m LEFT JOIN dbo.detailT d
ON m.Id = d.IdRif
WHERE d.Dati = 'Paperino1'
GROUP BY m.Dati

restituisce solo

Oggetto Ricorrenze
---------- -----------
Paperino 1

mentre io vorrei

Oggetto Ricorrenze
---------- -----------
Paperino 1
Topolino 0
vuoto 0

Si può fare?

Grazie.
Luciano
53 messaggi dal 15 novembre 2004
Ho trovato una soluzione:

SELECT m.dati AS [Oggetto],
[Ricorrenze] = (SELECT COUNT(*) FROM dbo.detailT d
WHERE
d.Dati = 'Paperino1' AND d.IdRif =m.Id)
FROM dbo.masterT m

ma temo che sia lenta con molti record perchè esegue una select per ciascuna riga.

Luciano
215 messaggi dal 07 settembre 2005
SELECT m.dati AS [Oggetto], COUNT(d.Id) AS [Ricorrenze]
FROM dbo.masterT m LEFT JOIN dbo.detailT d
ON m.Id = d.IdRif
WHERE d.Dati = 'Paperino1' Or d.Dati Is Null
GROUP BY m.Dati

Così dovrebbe andare e forse è anche veloce.


Ciao.
Riccardo.
-----Messaggio originale-----
Da: sql_server_e_mysql@forum.aspitalia.com
sql_server_e_mysql@forum.aspitalia.com] Per conto di luciano.netInviato: giovedì 15 settembre 2005 20.01
A: sql_server_e_mysql@forum.aspitalia.com
Oggetto: [sql_server_e_mysql] [246266] Re: Istruzione COUNT

Ho trovato una soluzione:

SELECT m.dati AS [Oggetto],
[Ricorrenze] = (SELECT COUNT(*) FROM dbo.detailT d
WHERE
d.Dati = 'Paperino1' AND d.IdRif =m.Id)
FROM dbo.masterT m

ma temo che sia lenta con molti record perchè esegue una select perciascuna riga.

Luciano
1.976 messaggi dal 27 luglio 2005
Contributi
salve,
cyber_man ha scritto:
SELECT m.dati AS [Oggetto], COUNT(d.Id) AS [Ricorrenze]
FROM dbo.masterT m LEFT JOIN dbo.detailT d
ON m.Id = d.IdRif
WHERE d.Dati = 'Paperino1' Or d.Dati Is Null
GROUP BY m.Dati

Così dovrebbe andare e forse è anche veloce.


meglio
SELECT m.dati AS [Oggetto], COUNT(d.Id) AS [Ricorrenze]
FROM dbo.masterT m LEFT JOIN (SELECT * FROM dbo.detailT d WHERE d.dati='paperino1') d
ON m.Id = d.IdRif
GROUP BY m.Dati
che correttamente esegue
|--Compute Scalar(DEFINE:([Expr1002]=Convert([Expr1005])))
|--Stream Aggregate(GROUP BY:([m].[Dati]) DEFINE:([Expr1005]=COUNT_BIG([d].[Id])))
|--Sort(ORDER BY:([m].[Dati] ASC))
|--Nested Loops(Left Outer Join, WHERE:([m].[Id]=[d].[IdRif]))
|--Clustered Index Scan(OBJECT:([tempdb].[dbo].[masterT].[PK__masterT__59FA5E80] AS [m]))
|--Clustered Index Scan(OBJECT:([tempdb].[dbo].[detailT].[PK__detailT__5BE2A6F2] AS [d]), WHERE:([d].[Dati]='paperino1'))

e correttamente ritorna
--<------------
Oggetto Ricorrenze
---------- -----------
Paperino 1
Topolino 0
vuoto 0

Warning: Null value is eliminated by an aggregate or other SET operation.

dove la tua proiezione ritorna
--<------------
Oggetto Ricorrenze
---------- -----------
Paperino 1
vuoto 0

saluti

Andrea Montanari
http://www.hotelsole.com - http://www.hotelsole.com/asql/index.php
53 messaggi dal 15 novembre 2004
La soluzione di cyber_man
SELECT m.dati AS [Oggetto], COUNT(d.Id) AS [Ricorrenze]
FROM dbo.masterT m LEFT JOIN dbo.detailT d
ON m.Id = d.IdRif
WHERE d.Dati = 'Paperino1' Or d.Dati Is Null
GROUP BY m.Dati

non va bene perchè non restituisce 'Topolino', che ha dati diversi da 'Paperino1' e quindi non rientra nella clausola WHERE (non ha un record NULL nella vista);
quella di Andrea Montanari
SELECT m.dati AS [Oggetto], COUNT(d.Id) AS [Ricorrenze]
FROM dbo.masterT m LEFT JOIN (SELECT * FROM dbo.detailT d WHERE d.dati='paperino1') d
ON m.Id = d.IdRif
GROUP BY m.Dati

restituisce correttamente i tre record, ho però qualche perplessità sulle prestazioni, considerando anche che nel mio caso la clausola WHERE è complessa e poi devo ordinare i dati in base a due campi. Questa mattina farò qualche test e vi terrò aggiornati.

Grazie

Luciano
215 messaggi dal 07 settembre 2005
Hei ragione!
Questa però è OK ma andrebbe prrovata su qualche milione di record percapire la velocità rispetto alla tua.

SELECT dbo.MasterT.dati, SUM(CASE WHEN Detail.Dati = 'Paperino1' THEN 1ELSE 0 END) AS Ricorrenze
FROM dbo.MasterT LEFT OUTER JOIN
dbo.Detail ON dbo.MasterT.id = dbo.Detail.idRifGROUP BY dbo.MasterT.dati

Che correttamente ritorna:
paperino 1
pippo 0
pluto 0


Ciao.
Riccardo.
-----Messaggio originale-----
Da: sql_server_e_mysql@forum.aspitalia.com
sql_server_e_mysql@forum.aspitalia.com] Per conto di AndreaMontanari [MVP]
Inviato: venerdì 16 settembre 2005 0.46
A: sql_server_e_mysql@forum.aspitalia.com
Oggetto: [sql_server_e_mysql] [246273] Re: RE: Istruzione COUNT
salve,
cyber_man ha scritto:

SELECT m.dati AS [Oggetto], COUNT(d.Id) AS [Ricorrenze] FROM dbo.masterT m LEFT JOIN dbo.detailT d
ON m.Id = d.IdRif
WHERE d.Dati = 'Paperino1' Or d.Dati Is Null
GROUP BY m.Dati

Così dovrebbe andare e forse è anche veloce.


meglio
SELECT m.dati AS [Oggetto], COUNT(d.Id) AS [Ricorrenze]
FROM dbo.masterT m LEFT JOIN (SELECT * FROM dbo.detailT d WHEREd.dati='paperino1') d
ON m.Id = d.IdRif
GROUP BY m.Dati
che correttamente esegue
|--Compute Scalar(DEFINE [Expr1002]=Convert([Expr1005])))
|--Stream Aggregate(GROUP BY [m].[Dati])
DEFINE [Expr1005]=COUNT_BIG([d].[Id])))
|--Sort(ORDER BY [m].[Dati] ASC))
|--Nested Loops(Left Outer Join,
WHERE [m].[Id]=[d].[IdRif]))
|--Clustered Index
Scan(OBJECT [tempdb].[dbo].[masterT].[PK__masterT__59FA5E80] AS [m]))|--Clustered Index
Scan(OBJECT [tempdb].[dbo].[detailT].[PK__detailT__5BE2A6F2] AS [d]),WHERE [d].[Dati]='paperino1'))

e correttamente ritorna
--<------------
Oggetto Ricorrenze
--------
-----------
Paperino 1
Topolino 0
vuoto 0

Warning: Null value is eliminated by an aggregate or other SET operation.
dove la tua proiezione ritorna
--<------------
Oggetto Ricorrenze
--------
-----------
Paperino 1
vuoto 0

saluti

Torna al forum | Feed RSS

ASPItalia.com non è responsabile per il contenuto dei messaggi presenti su questo servizio, non avendo nessun controllo sui messaggi postati nei propri forum, che rappresentano l'espressione del pensiero degli autori.