2015-07-21 11 views
7

Sto usando SQL-Server 2008. Ho bisogno di combinare le righe con la stessa Name e aumento contatore quando:Combina righe se il valore è vuoto

  1. 1 o più Id's per lo stesso Name è blank
  2. Non unire righe se Id è NULL!
  3. NON unire righe se abbia la stessa Name, ma diversi Ids

Uscita per ora:

Name Id Cnt 
John 1  1 
Peter 2  2 -- This Peter with the same Id have 2 entries so Cnt = 2 
Peter 3  1 -- This is other Peter with 1 entry so Cnt = 1 
Lisa 4  1 
Lisa NULL 1 
David 5  1 
David   1 -- here Id is blank '' 
Ralph   2 -- Ralph have both rows with blank Id so Cnt = 2 

output desiderato:

Name Id Cnt 
John 1  1 
Peter 2  2 
Peter 3  1 
Lisa 4  1 
Lisa NULL 1 -- null still here 
David 5  2 -- merged with blank '' so Cnt = 2 
Ralph   2 -- merged both blanks '' so Cnt = 2 

SQL-Query :

Si tratta di query di esempio quello che sto usando per ora:

SELECT Name, 
     Id, 
     COUNT(Id) AS Cnt 
FROM Employees      
WHERE Condition = 1     
GROUP BY Name, Id 

Quello che ho cercato:

Aggiunto aggregato MAX-Id in SELECT clausola e raggruppati da solo Name, ma in questo caso le righe unite con i valori NULL e con gli stessi nomi con diverso Id's cosa c'è che non va.

SELECT Name, 
     MAX(Id), -- added aggregate 
     COUNT(Id) AS Cnt 
FROM Employees      
WHERE Condition = 1     
GROUP BY Name -- grouped by Name only 

Avete qualche idea? Se qualcosa non è chiaro sul problema - chiedimi, fornirò maggiori dettagli.

UPDATE:

DDL

CREATE TABLE Employees 
(
    Name NVARCHAR(40), 
    Id NVARCHAR(40) 
); 

DML

INSERT INTO Employees VALUES 
('John' , '1') 
,('Peter', '2') 
,('Peter', '2') 
,('Peter', '3') 
,('Lisa' , '4') 
,('Lisa' , NULL) 
,('David', '5') 
,('David', '') 
,('Ralph', '') 
,('Ralph', '') 

DEMO:SQL FIDDLE

+0

+1 per una domanda ben formata. tuttavia, è meglio includere le tabelle rilevanti ddl + dml per i dati di esempio in modo che chiunque voglia rispondere sia in grado di riprodurlo facilmente. –

+1

Progettazione strana di dati nella tabella ... Prenderesti in considerazione i dati di modifica? – Anton

+0

@ZoharPeled secondo, fornirò DDL + DML –

risposta

1

Modifica

DECLARE @Data table (Name varchar(10), Id varchar(10)) -- Id must be varchar for blank value 
INSERT @Data VALUES 
('John', '1'), 
('Peter', '2'),('Peter', '2'), 
('Peter', '3'),--('Peter', ''), --For test 
('Lisa', '4'), 
('Lisa', NULL), 
('David', '5'), 
('David', ''), 
('Ralph', ''), ('Ralph', '') 

SELECT 
    Name, 
    Id, 
    COUNT(*) + ISNULL(
     (SELECT COUNT(*) FROM @data WHERE Name = d.Name AND Id = '' AND d.Id <> '') 
    , 0) AS Cnt 
FROM @data d 
WHERE 
    Id IS NULL 
    OR Id <> '' 
    OR NOT EXISTS(SELECT * FROM @data WHERE Name = d.Name AND Id <> '') 
GROUP BY Name, Id 
+0

@ StanislovasKalašnikovas Vedi modifica – Eric

1

È possibile utilizzare la dichiarazione CASE all'interno di SELECT. Ti permette di impostare Id = [qualche valore] per i dipendenti in cui è vuoto.Query può essere qualcosa di simile:

SELECT E.Name, 
      CASE 
        WHEN E.Id = '' 
        THEN 
         (Select Employees.Id from Employees where Employees.Id <> '' and E.Name = Employees.Name) 
        ELSE E.Id 
      END as Idx, 
     COUNT(Id) AS Cnt 
FROM Employees as E      
WHERE Condition = 1     
GROUP BY Name, Idx 
0

Prova questa. utilizzando cte e si unisce

;with cte as (
SELECT Name, 
     Id, 
     COUNT(*) AS Cnt 
FROM Employees      
WHERE isnull(Id,1)<>''    
GROUP BY Name, Id 
), 

cte2 as (SELECT Name,id, COUNT(*) AS Cnt FROM Employees WHERE Id='' GROUP BY Name,id) 

select cte.Name,cte.Id,(cte.cnt + ISNULL(cte2.Cnt,0)) as cnt 
from cte 
left JOIN cte2 
on cte.Name = cte2.Name 
union all 
select cte2.Name,cte2.Id,cte2.cnt 
from cte2 
left JOIN cte 
on cte.Name = cte2.Name 
where cte.Name is null 
1

Una versione con funzioni finestra:

SELECT Name,ID, Cnt from 
(select *, sum(1-AmtBlank) over (partition by Name, ID) + sum(case id when 0 then 1 else 0 end) over (partition by Name) Cnt, 
     rank() over (partition by Name order by AmtBlank ) rnk, 
     row_number() over (partition by Name, ID order by AmtBlank) rnr 
    FROM (select * , case id when '' then 1 else 0 end AmtBlank from Employees /*WHERE Condition = 1*/) e 
) c where rnr=1 and rnk = 1 

Questo utilizza case id when '' then 1 else 0 end AmtBlank di mantenere un importo per gli importi in bianco per riga (rendendo la quantità di non fustellati 1-AmtBlank) e 2 funzioni della finestra, una con ID per un conteggio per nome e ID (sum(1-AmtBlank) over (partition by Name, ID)) e un conteggio per tutti gli spazi in una sezione nome (sum(case id when 0 then 1 else 0 end) over (partition by Name)) Il row_number viene utilizzato per recuperare successivamente solo le prime righe di un gruppo e rank viene utilizzato solo includere i record vuoti whe n non ci sono record con un id.

0

Questo semplice sintassi è compatibile con le versioni precedenti o altri RDBMS
- Auto spiegato commenti
Modificato:

select name, id, count(*) from (
    -- adds "normal" records 
    select name, id from Employees where id is null or id <> '' 
    -- adds one record to each name-notBlankId for each blank id (David, Peter if you add 'Peter','') 
    -- uncomment /*or id is null*/ if you want even null ids to recieve merged blanks 
    union all 
    select e1.name, e1.id 
    from (select distinct name, id from Employees where id <> '' /*or id is null*/) as e1 
    inner join (select name, id from Employees where id = '') as e2 on e1.name = e2.name 
    -- adds records that can't be merged (Ralph) 
    union all 
    select name, id from Employees e1 
    where e1.id = '' 
     and not exists(select * from Employees e2 where e1.name = e2.name and e2.id <> '') 
) as fullrecords 
group by name, id 
0

Si potrebbe provare qualcosa di simile.

;WITH NonBlanks AS 
(
    SELECT Name, 
     Id, 
     COUNT(ISNULL(Id, 1)) AS Cnt 
    FROM Employees 
    WHERE ISNULL(Id,0) <> '' 
    GROUP BY Name, Id 
) 
,Blanks AS 
(
    SELECT Name, 
     Id, 
     COUNT(ISNULL(Id, 1)) AS Cnt 
    FROM Employees 
    WHERE ID = '' 
    GROUP BY Name, Id 
) 
SELECT CASE WHEN nb.NAME IS NULL THEN b.NAME ELSE nb.NAME END NAME, 
     CASE WHEN nb.NAME IS NULL THEN b.Id ELSE nb.Id END Id, 
     (ISNULL(nb.Cnt,0) + ISNULL(b.Cnt,0)) Cnt 
FROM NonBlanks nb FULL JOIN Blanks b 
    ON nb.Name = b.Name