64 messaggi dal 04 gennaio 2007
www.zamba.it
Devo fare una query di selezione con DISTINCT e contare i campi distinti secondo un flag presente in una colonna del database stesso, ma non riesco a tirare fuori i dati in maniera giusta.
Mi spiego meglio. Questa è la query che ho scritto.

SELECT DISTINCT Servizio, COUNT(ClientePerso) AS Serviti
FROM tblElencoPrenotazioni
GROUP BY Servizio, ClientePerso

Dove ClientePerso è la colonna con valore TRUE/FALSE

Ma mi restituisce questo risultato.

BOLLETTINI57
BOLLETTINI177
CORRISPONDENZA E PACCHI43
CORRISPONDENZA E PACCHI74
IMPRESA14
IMPRESA30
RISERVATO CONTO42
RISERVATO CONTO65
SERVIZI FINANZIARI62
SERVIZI FINANZIARI99
SPORTELLO AMICO8
SPORTELLO AMICO9

io vorrei che mi selezionasse i risultati cosi

BOLLETTINI 57 177
CORRISPONDENZA E PACCHI43 74
Ecc.....

Qualche guru di SQL mi puo aiutare?
1.976 messaggi dal 27 luglio 2005
Contributi
salve,
devi effettuare una "rotazione" di riga su colonna, e si puo' fare in svariati modi...
ti elenco la forma piu' semplice, effettuata via SUM( CASE WHEN colonna=filtro THEN 1 ELSE 0 END), che e' la modialita' piu' tradizionale e semplice da gestire..
di seguito una doppia aggregazione con filtro di ricerca per i 2 possibili valori e JOIN dei risultati, ed infine la "classica" metodologia di PIVOTing fornita da SQL Server... personalmente non ho mai amato l'ultima e preferisco la prima, ma vedi tu...

SET NOCOUNT ON;
USE tempdb;
GO
CREATE TABLE dbo.Tipologia (
  Id int NOT NULL PRIMARY KEY,
  Descrizione varchar(25) NOT NULL
  );
CREATE TABLE dbo.ElencoPrenotazioni (
  Id int PRIMARY KEY IDENTITY,
  IdTipo int NOT NULL
  CONSTRAINT fk_ElencoPrenotazioni$has$Tipologia
  FOREIGN KEY REFERENCES dbo.Tipologia(id),
  ClientePerso bit NOT NULL
  )
GO
INSERT INTO dbo.Tipologia
  VALUES (1, 'BOLLETTINI'), (2, 'CORRISPONDENZA E PACCHI'), (3, 'IMPRESA')
  , (4, 'Tutti Buoni'), (5, 'Solo Persi');

DECLARE @Loop int = 1;
WHILE @Loop <=100 BEGIN
  DECLARE @Perso bit = 0;
  IF @Loop % 3 = 0 SET @Perso = 1;
  INSERT INTO dbo.ElencoPrenotazioni (IdTipo, ClientePerso)
    VALUES ( 1, @Perso );
  
  
  SET @Perso = 0;
  IF @Loop % 5 = 0 SET @Perso = 1;
  INSERT INTO dbo.ElencoPrenotazioni (IdTipo, ClientePerso)
    VALUES ( 2, @Perso );

  SET @Perso = 0;
  IF @Loop % 7 = 0 SET @Perso = 1;
  INSERT INTO dbo.ElencoPrenotazioni (IdTipo, ClientePerso)
    VALUES ( 3, @Perso );

  SET @Loop +=1;
END;

INSERT INTO dbo.ElencoPrenotazioni (IdTipo, ClientePerso)
  VALUES ( 4, 0 );

INSERT INTO dbo.ElencoPrenotazioni (IdTipo, ClientePerso)
  VALUES ( 5, 1 );

GO
--SELECT * 
--  FROM dbo.ElencoPrenotazioni e
--    JOIN dbo.Tipologia t ON e.[IdTipo] = t.[Id];

SELECT t.[Descrizione], e.[ClientePerso], COUNT(*) AS [Conto]
  FROM dbo.ElencoPrenotazioni e
    JOIN dbo.Tipologia t ON e.[IdTipo] = t.[Id]
  GROUP BY t.[Descrizione], e.[ClientePerso];

PRINT 'Raggruppamento via Validita'' con aggregazione condizionata';
SELECT t.[Descrizione]
  , SUM( CASE WHEN e.[ClientePerso] = 0 THEN 1 ELSE 0 END ) AS [ContoBuono]
  , SUM( CASE WHEN e.[ClientePerso] = 1 THEN 1 ELSE 0 END ) AS [Persi]  
  FROM dbo.ElencoPrenotazioni e
    JOIN dbo.Tipologia t ON e.[IdTipo] = t.[Id]
  GROUP BY t.[Descrizione];

PRINT '--';
PRINT 'Raggruppamento via aggregazione partizionata e JOIN dei risultati';
WITH cte1 AS (
  SELECT t.[Descrizione], e.[ClientePerso], COUNT(*) AS [Conto]
    FROM dbo.ElencoPrenotazioni e
      JOIN dbo.Tipologia t ON e.[IdTipo] = t.[Id]
    WHERE e.[ClientePerso] = 0
    GROUP BY t.[Descrizione], e.[ClientePerso]    
  ),
cte2 AS (
  SELECT t.[Descrizione], e.[ClientePerso], COUNT(*) AS [Conto]
    FROM dbo.ElencoPrenotazioni e
      JOIN dbo.Tipologia t ON e.[IdTipo] = t.[Id]
    WHERE e.[ClientePerso] = 1
    GROUP BY t.[Descrizione], e.[ClientePerso]    
)
-- sostituito con FULL OUTER JOIN
SELECT ISNULL(c1.[Descrizione], c2.[Descrizione]) AS [Descrizione]
  , ISNULL(c1.[Conto], 0) AS [ContoBuono]
  , ISNULL(c2.[Conto], 0) AS [Persi]
  FROM cte1 c1
    FULL OUTER JOIN cte2 c2 ON c1.[Descrizione] = c2.[Descrizione];
-- sostituito con FULL OUTER JOIN per
-- evitare la perdita di righe causa
-- evenutale mancanza di correlazione
--SELECT c1.[Descrizione], c1.[Conto] AS [ContoBuono], c2.[Conto] AS [Persi]
--  FROM cte1 c1
--    JOIN cte2 c2 ON c1.[Descrizione] = c2.[Descrizione];

PRINT '--';
PRINT 'Raggruppamento via PIVOTing';
SELECT [Descrizione], [0] AS [ContoBuono], [1] AS [Persi]
  FROM
  (SELECT t.[Descrizione], e.[ClientePerso]
    FROM dbo.ElencoPrenotazioni e
      JOIN dbo.Tipologia t ON e.[IdTipo] = t.[Id]
  ) AS SourceTable
  PIVOT
  (COUNT([ClientePerso]) FOR [ClientePerso] IN ([0],[1])) AS PivotTable;
  
GO
DROP TABLE dbo.ElencoPrenotazioni, dbo.Tipologia;
--<----------
Descrizione               ClientePerso Conto
------------------------- ------------ -----------
BOLLETTINI                0            67
CORRISPONDENZA E PACCHI   0            80
IMPRESA                   0            86
Tutti Buoni               0            1
BOLLETTINI                1            33
CORRISPONDENZA E PACCHI   1            20
IMPRESA                   1            14
Solo Persi                1            1

Raggruppamento via Validita' con aggregazione condizionata
Descrizione               ContoBuono  Persi
------------------------- ----------- -----------
BOLLETTINI                67          33
CORRISPONDENZA E PACCHI   80          20
IMPRESA                   86          14
Solo Persi                0           1
Tutti Buoni               1           0

--
Raggruppamento via aggregazione partizionata e JOIN dei risultati
Descrizione               ContoBuono  Persi
------------------------- ----------- -----------
BOLLETTINI                67          33
CORRISPONDENZA E PACCHI   80          20
IMPRESA                   86          14
Tutti Buoni               1           0
Solo Persi                0           1

--
Raggruppamento via PIVOTing
Descrizione               ContoBuono  Persi
------------------------- ----------- -----------
BOLLETTINI                67          33
CORRISPONDENZA E PACCHI   80          20
IMPRESA                   86          14
Solo Persi                0           1
Tutti Buoni               1           0



saluti
Modificato da Andrea Montanari il 18 dicembre 2015 13.47 - modificata la JOIN con FULL OUTER JOIN per evitare la perdita di righe causa evenutale mancanza di correlazione

Andrea Montanari
http://www.hotelsole.com - http://www.hotelsole.com/asql/index.php
64 messaggi dal 04 gennaio 2007
www.zamba.it
Quello che hai scritto è Fantastico, ma non riesco ad applicarlo al mio DB. Forse se mi fossi spiegato meglio dall'inizio..............
ho una tabella che contiene i SERVIZI in una colonna,(che devo contare in totale) poi una colonna ClientePerso, che ha un flags true/false i quali devono essere contati singolarmente.
Adesso con questa:

SELECT DISTINCT Servizio, COUNT(ClientePerso) AS Tot
FROM tblElencoPrenotazioni
GROUP BY Servizio

trovo questi dati

Servizio Tot
---------------------------
BOLLETTINI 234
CORRISPONDENZA E PACCHI117
IMPRESA 44
RISERVATO CONTO 107
SERVIZI FINANZIARI161
SPORTELLO AMICO 17

Ovviamente andando a modificare la Query aggiungendo la clausola HAVING (ClientePerso = true), seleziono quelli persi e anche gli altri scrivendo HAVING (ClientePerso = False).

Come posso usare la clausola CASE when..... per ottenere questo risultato?

Servizio Tot Serviti Persi
----------------------------------------------------------------
BOLLETTINI 234 177 57
CORRISPONDENZA E PACCHI117 74 43
IMPRESA 44 30 14
RISERVATO CONTO 107 65 42
SERVIZI FINANZIARI161 99 62
SPORTELLO AMICO 17 9 8

Inoltre dovrei farci delle operazioni matematiche su quei numeri, ma potrei anche operare intercettando il valore direttamente dalla cella del gridview.

Perdonatemi se non capisco.......ma non avrei scritto, altrimenti
1.976 messaggi dal 27 luglio 2005
Contributi
salve e Buon Natale...
tu non hai fornito uno scenario definito da CREATE TABLE e cosi' mi sono arrangiato... ma quello che chiedi mi pare gia' risolto...
SELECT t.[Descrizione]
  -- ho solo aggiunto questa riga per i totali
  , COUNT(*) AS [Tot]

  -- invariato da prima
  , SUM( CASE WHEN e.[ClientePerso] = 0 THEN 1 ELSE 0 END ) AS [Serviti]
  , SUM( CASE WHEN e.[ClientePerso] = 1 THEN 1 ELSE 0 END ) AS [Persi]  
  FROM dbo.ElencoPrenotazioni e
    JOIN dbo.Tipologia t ON e.[IdTipo] = t.[Id]
  GROUP BY t.[Descrizione];
--<------------
Descrizione               Tot         Serviti     Persi
------------------------- ----------- ----------- -----------
BOLLETTINI                100         67          33
CORRISPONDENZA E PACCHI   100         80          20
IMPRESA                   100         86          14
Solo Persi                1           0           1
Tutti Buoni               1           1           0


forse mi sono perso qualche cosa, ma non capisco la tua esigenza...

per quanto riguarda le "operazioni matematiche sul risultato", dipende cosa intendi farci.. se devi fare "medie" o "robe simili", probabilmente metterei quella query in una common table expression in modo da avere la prima aggregazione per tipologia gia' pronta, e poi... dipende :)
ad esempio, trivialmente,

-- CTE preaggregata
WITH cte AS (
SELECT t.[Descrizione]
  -- ho solo aggiunto questa riga per i totali
  , COUNT(*) AS [Tot]

  -- invariato da prima
  , SUM( CASE WHEN e.[ClientePerso] = 0 THEN 1 ELSE 0 END ) AS [Serviti]
  , SUM( CASE WHEN e.[ClientePerso] = 1 THEN 1 ELSE 0 END ) AS [Persi]  
  FROM dbo.ElencoPrenotazioni e
    JOIN dbo.Tipologia t ON e.[IdTipo] = t.[Id]
  GROUP BY t.[Descrizione]
  )
  -- utilizzo dati preaggregrati per altre operazioni...
  SELECT c.Descrizione, c.Tot, c.Serviti, c.Persi
    , CONVERT(decimal(5,2), CONVERT(decimal(5,2), c.Serviti) / c.Tot * 100) AS [% Serviti]
    , CONVERT(decimal(5,2), CONVERT(decimal(5,2), c.Persi) / c.Tot * 100) AS [% Persi]
    FROM cte c;
--<-------
Descrizione               Tot         Serviti     Persi       % Serviti     % Persi
------------------------- ----------- ----------- ----------- ------------- ---------
BOLLETTINI                100         67          33          67.00         33.00
CORRISPONDENZA E PACCHI   100         80          20          80.00         20.00
IMPRESA                   100         86          14          86.00         14.00
Solo Persi                1           0           1           0.00          100.00
Tutti Buoni               1           1           0           100.00        0.00



saluti e buon anno :) :)
Modificato da Andrea Montanari il 29 dicembre 2015 17.42 -

Andrea Montanari
http://www.hotelsole.com - http://www.hotelsole.com/asql/index.php
64 messaggi dal 04 gennaio 2007
www.zamba.it
Ciao Andrea, tutto cio che mi hai scritto mi ha aiutato a capire molto, e ti ringrazio.
In realta non ti avevo scritto che lavoro con file di access (il sistema mi rilascia solo questi database, e ho risolto cosi

SELECT Servizio, COUNT(ClientePerso) AS tot, tot - NonServiti AS Serviti, SUM(IIF(ClientePerso, 1, 0)) AS NonServiti
FROM tblElencoPrenotazioni
GROUP BY Servizio

Servizio tot Serviti NonServiti
----------------------------------------------------------
BOLLETTINI23417757
CORRISPONDENZA E PACCHI1177443
IMPRESA443014
RISERVATO CONTO1076542
SERVIZI FINANZIARI1619962
SPORTELLO AMICO1798

Ho dovuto usare IIf che e supportato da Access.

Visto che sei veramente forte e disponibile, puoi dirmi come potrei fare ad inserire tramite la query i risultati dei totali, ma per colonna, non per riga, aggiungendo una riga in fondo che si chiama TOTALE. Si puo?
Tanti auguri di Buon Anno nuovo a te e a tutta la tua Famiglia.
1.976 messaggi dal 27 luglio 2005
Contributi
salve e buon anno,
Willys70 ha scritto:
... puoi dirmi come potrei fare ad inserire tramite la query i risultati dei totali, ma per colonna, non per riga, aggiungendo una riga in fondo che si chiama TOTALE. Si puo?
Tanti auguri di Buon Anno nuovo a te e a tutta la tua Famiglia.

dovresti aggiungere alla prima proiezione la seconda proiezione senza raggruppamento, quindi qualche cosa simile a
SELECT DISTINCT Servizio, COUNT(ClientePerso) AS Serviti
  FROM tblElencoPrenotazioni
  GROUP BY Servizio, ClientePerso
UNION
SELECT DISTINCT Servizio, COUNT(ClientePerso) AS Serviti
  FROM tblElencoPrenotazioni



saluti

Andrea Montanari
http://www.hotelsole.com - http://www.hotelsole.com/asql/index.php

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.