2015-07-21 42 views
7

我正在使用SQL-Server 2008。我需要行與同Name和增加計數器相結合時:如果值爲空,則合併行

  1. 1個或多個Id's爲同一Nameblank
  2. 如果IdNULL不會合並行!
  3. 如果有相同的Name不會合並行,但不同Ids

輸出現在:

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 

所需的輸出:

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查詢:

這是我使用的是什麼樣,現在查詢:

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

我曾嘗試:

SELECT條款總增加MAXId和分組僅Name,但在這種情況下合併的行與NULL值和相同的名稱不同Id's我什麼是錯的。

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

你有什麼想法嗎?如果有什麼不清楚的問題 - 問我,我會提供更多的細節。

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。但是,最好將示例數據的相關表格ddl + dml包含在內,以便任何想要回答的人都能夠輕鬆地重現該表格。 –

+1

表格中數據的奇怪設計...您會考慮更改數據嗎? – Anton

+0

@Zohar第二,我會提供DDL + DML –

回答

1

編輯

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請參閱編輯 – Eric

1

您可以在SELECT內使用CASE聲明。它允許你爲員工設置Id = [某些值],它是空白的。查詢可以是這樣的:

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

試試這個。使用CTE並加入

;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

與窗函數的版本:

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 

這使用case id when '' then 1 else 0 end AmtBlank保持的量爲每行的空白量(使量的非空白1- AmtBlank)和2窗口函數,其中一個帶有用於每個名稱和ID的計數(sum(1-AmtBlank) over (partition by Name, ID))和用於名稱部分中的所有空白的計數(sum(case id when 0 then 1 else 0 end) over (partition by Name)row_number用於隨後僅提取組的第一行並且rank僅用於僅用於包括空白記錄n沒有記錄帶有ID。

0

這種簡單的語法與舊版本或其他RDBMS
兼容 - 自上留言解釋
編輯:

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

你可以嘗試這樣的事情。

;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 
相關問題