2016-10-04 251 views
4

這裏是我的樣本數據:計數基於字符串和空

id  FirstName  LastName  HouseNo  MyCount 
1  A     C   1-1   2 
2  B     C   1-1   2 
4  D     A      3 
5  F     A      3 
6  J     A      3 
7  Q     X   1-2   3 
8  D     X   1-2   3 
9  D     X   1-2   3 
10  A     C   1-3   3 
11  B     C   1-3   3 
12  C     C   1-3   3 
14  F     K      2 
15  J     K      2 
16  Q     X   1-5   1 

通過上述數據我想利用的記錄數與同HouseNoLastName

對於這個我使用

SELECT COUNT(ID) AS _COUNT FROM MYTABLE GROUP BY LASTNAME, HOUSENO 

但上面的語句有一個問題。在數據中有些記錄沒有HouseNo。在上面的例子中,ID 4,5,6和14,15沒有HouseNo。所以,上面的語句返回5,但它應該分別返回3和2。

主要目的

  1. 採取基於LastNameHouseNo
  2. 計取不具有HouseNo這些記錄的計數(他們將進來系列)。
  3. 即將到來的數應在MyCount

更新我如何獲得這算什麼?

編輯獎勵:

示例數據

id FirstName LastName HouseNo  MyCount  CountId 
1 Imran  Khan  1-1   
2 Waseem  Khan  1-1   
3 Rihan  Khan  1-1   
4 Moiz  Shaikh  1-2   
5 Zbair  Shaikh  1-2   
6 Sultan  Shaikh  1-2   
7 Zaid  Khan      
10 Parvez  Patel  1-3   
11 Ahmed  Patel  1-3   
12 Rahat  Syed  1-4   
13 Talha  Khan      
14 Zia   Khan      
15 Arshad  Patel  1-3   
16 Samad  Patel  1-3   
17 Raees  Syed  1-4   
18 Azmat  Khan      
19 Imran  Khan      

預期結果:

id FirstName LastName HouseNo  MyCount  CountId 
1 Imran  Khan  1-1   3   1 
2 Waseem  Khan  1-1   3   1 
3 Rihan  Khan  1-1   3   1 
4 Moiz  Shaikh  1-2   3   2 
5 Zbair  Shaikh  1-2   3   2 
6 Sultan  Shaikh  1-2   3   2 
7 Zaid  Khan     1   3 
10 Parvez  Patel  1-3   2   4 
11 Ahmed  Patel  1-3   2   4 
12 Rahat  Syed  1-4   1   5 
13 Talha  Khan     2   6 
14 Zia   Khan     2   6 
15 Arshad  Patel  1-3   2   7 
16 Samad  Patel  1-3   2   7 
17 Raees  Syed  1-4   1   8 
18 Azmat  Khan     2   9 
19 Imran  Khan     2   9 
  1. 在樣本數據MyCountCountId是空白的,應該填充。
  2. MyCount將根據HouseNoLastName,請參閱ID爲1〜3,其最後的名字叫可汗與房子沒有那麼1-1號1的MyCount 3將是3,和CountId將1
  3. 在樣本數據中有許多記錄沒有HouseNo,因此在這種情況下,系列中的同一姓氏將被計數。請參閱ID 7,其計數將爲1.另請參見ID 18和19,其計數將爲2.
  4. CountId是ID計數的序列號。請參見ID 1至3,由於同一房屋號碼和相同姓氏而爲1。
+0

您由LASTNAME,HOUSENO分組。 A/NULL和K/NULL顯然是兩個不同的組,所以我沒有看到你的查詢如何給你一個5的合併計數。請問'SELECT LASTNAME,HOUSENO,COUNT(ID)'而不是'SELECT COUNT(ID)',以查看哪個組獲得5的計數? –

+0

我剛剛檢查過它。您的查詢 - 除了錯字GRUOP/GROUP之外,*不會*返回5,而是分別返回3和2,就像您想要的一樣,並且我確信它會。這裏是SQL小提琴:http://sqlfiddle.com/#!6/c536b/2。所以你可以在我看來完全刪除這個問題。 –

回答

4

它看起來像主的混亂是由你的SQL語句的問題,你只需GROUP BY LASTNAME, HOUSENO的開始引起落實。

如果你想要一個簡單的分組,你的查詢將是正確的。但是,那麼您向我們展示了一個具有預期結果的更詳細的示例數據,並且很明顯,您不僅需要一個分組(它不關心數據中行的順序),而且希望根據它們對行進行分組序列。

這是一個經典問題gaps-and-islands。在SQL Server 2008中,可以使用對ROW_NUMBER函數的少量調用來完成。

的樣本數據

DECLARE @T TABLE 
    (id int PRIMARY KEY 
    ,FirstName nvarchar(50) 
    ,LastName nvarchar(50) 
    ,HouseNo nvarchar(50) 
    ,MyCount int 
    ,CountId int); 

INSERT INTO @T (id, FirstName, LastName, HouseNo) VALUES 
(1 , 'Imran ', 'Khan ', '1-1'), 
(2 , 'Waseem', 'Khan ', '1-1'), 
(3 , 'Rihan ', 'Khan ', '1-1'), 
(4 , 'Moiz ', 'Shaikh', '1-2'), 
(5 , 'Zbair ', 'Shaikh', '1-2'), 
(6 , 'Sultan', 'Shaikh', '1-2'), 
(7 , 'Zaid ', 'Khan ', NULL), 
(10, 'Parvez', 'Patel ', '1-3'), 
(11, 'Ahmed ', 'Patel ', '1-3'), 
(12, 'Rahat ', 'Syed ', '1-4'), 
(13, 'Talha ', 'Khan ', NULL), 
(14, 'Zia ', 'Khan ', NULL), 
(15, 'Arshad', 'Patel ', '1-3'), 
(16, 'Samad ', 'Patel ', '1-3'), 
(17, 'Raees ', 'Syed ', '1-4'), 
(18, 'Azmat ', 'Khan ', NULL), 
(19, 'Imran ', 'Khan ', NULL); 

SELECT查詢

WITH 
CTE_RN 
AS 
(
    SELECT 
     id 
     ,FirstName 
     ,LastName 
     ,HouseNo 
     ,MyCount 
     ,CountId 
     ,ROW_NUMBER() OVER (PARTITION BY LastName, HouseNo ORDER BY ID) AS rn1 
     ,ROW_NUMBER() OVER (ORDER BY ID) AS rn2 
    FROM @T AS T 
) 
,CTE_GRoups 
AS 
(
    SELECT 
     id 
     ,FirstName 
     ,LastName 
     ,HouseNo 
     ,MyCount 
     ,CountId 
     ,rn1 
     ,rn2 
     ,rn2-rn1 AS GroupNumber 
     ,COUNT(ID) OVER (PARTITION BY LastName, HouseNo, rn2-rn1) AS NewMyCount 
     ,MIN(ID) OVER (PARTITION BY LastName, HouseNo, rn2-rn1) AS GroupMinID 
    FROM CTE_RN 
) 
SELECT 
    id 
    ,FirstName 
    ,LastName 
    ,HouseNo 
    ,rn1 
    ,rn2 
    ,GroupNumber 
    ,NewMyCount 
    ,GroupMinID 
    ,DENSE_RANK() OVER (ORDER BY GroupMinID) AS NewCountId 
FROM CTE_GRoups 
ORDER BY ID; 

結果

+----+-----------+----------+---------+-----+-----+-------------+------------+------------+------------+ 
| id | FirstName | LastName | HouseNo | rn1 | rn2 | GroupNumber | NewMyCount | GroupMinID | NewCountId | 
+----+-----------+----------+---------+-----+-----+-------------+------------+------------+------------+ 
| 1 | Imran  | Khan  | 1-1  | 1 | 1 |   0 |   3 |   1 |   1 | 
| 2 | Waseem | Khan  | 1-1  | 2 | 2 |   0 |   3 |   1 |   1 | 
| 3 | Rihan  | Khan  | 1-1  | 3 | 3 |   0 |   3 |   1 |   1 | 
| 4 | Moiz  | Shaikh | 1-2  | 1 | 4 |   3 |   3 |   4 |   2 | 
| 5 | Zbair  | Shaikh | 1-2  | 2 | 5 |   3 |   3 |   4 |   2 | 
| 6 | Sultan | Shaikh | 1-2  | 3 | 6 |   3 |   3 |   4 |   2 | 
| 7 | Zaid  | Khan  | NULL | 1 | 7 |   6 |   1 |   7 |   3 | 
| 10 | Parvez | Patel | 1-3  | 1 | 8 |   7 |   2 |   10 |   4 | 
| 11 | Ahmed  | Patel | 1-3  | 2 | 9 |   7 |   2 |   10 |   4 | 
| 12 | Rahat  | Syed  | 1-4  | 1 | 10 |   9 |   1 |   12 |   5 | 
| 13 | Talha  | Khan  | NULL | 2 | 11 |   9 |   2 |   13 |   6 | 
| 14 | Zia  | Khan  | NULL | 3 | 12 |   9 |   2 |   13 |   6 | 
| 15 | Arshad | Patel | 1-3  | 3 | 13 |   10 |   2 |   15 |   7 | 
| 16 | Samad  | Patel | 1-3  | 4 | 14 |   10 |   2 |   15 |   7 | 
| 17 | Raees  | Syed  | 1-4  | 2 | 15 |   13 |   1 |   17 |   8 | 
| 18 | Azmat  | Khan  | NULL | 4 | 16 |   12 |   2 |   18 |   9 | 
| 19 | Imran  | Khan  | NULL | 5 | 17 |   12 |   2 |   18 |   9 | 
+----+-----------+----------+---------+-----+-----+-------------+------------+------------+------------+ 

在這裏,我包括在結果所有中間步驟,所以你可以看到它是如何工作的。主要部分是兩套ROW_NUMBER s。 rn1序列重新啓動爲每個LastName, HouseNo。它由LastName, HouseNo分區。 rn2是一個簡單的增加序列沒有差距。我們需要它,因爲原始ID定義了順序,但可能有空白。

然後我們減去這兩個序列,差異給我們GroupNumber

計算組中元素的數量很簡單COUNT,這給了我們NewMyCount

用兩個步驟完成無間隙序列號的枚舉。起初MIN給出了一個組的標識符,然後DENSE_RANK生成一個沒有間隙的序列NewCountId


如果你想真正與計算NewMyCountNewCountId更新原來​​的表,很容易打開SELECT上面的查詢到UPDATE查詢:

UPDATE查詢

WITH 
CTE_RN 
AS 
(
    SELECT 
     id 
     ,FirstName 
     ,LastName 
     ,HouseNo 
     ,MyCount 
     ,CountId 
     ,ROW_NUMBER() OVER (PARTITION BY LastName, HouseNo ORDER BY ID) AS rn1 
     ,ROW_NUMBER() OVER (ORDER BY ID) AS rn2 
    FROM @T AS T 
) 
,CTE_GRoups 
AS 
(
    SELECT 
     id 
     ,FirstName 
     ,LastName 
     ,HouseNo 
     ,MyCount 
     ,CountId 
     ,rn1 
     ,rn2 
     ,rn2-rn1 AS GroupNumber 
     ,COUNT(ID) OVER (PARTITION BY LastName, HouseNo, rn2-rn1) AS NewMyCount 
     ,MIN(ID) OVER (PARTITION BY LastName, HouseNo, rn2-rn1) AS GroupMinID 
    FROM CTE_RN 
) 
,CTE_Update 
AS 
(
    SELECT 
     id 
     ,FirstName 
     ,LastName 
     ,HouseNo 
     ,MyCount 
     ,CountId 
     ,rn1 
     ,rn2 
     ,GroupNumber 
     ,NewMyCount 
     ,GroupMinID 
     ,DENSE_RANK() OVER (ORDER BY GroupMinID) AS NewCountId 
    FROM CTE_GRoups 
) 
UPDATE CTE_Update 
SET 
    MyCount = NewMyCount 
    ,CountId = NewCountId 
; 

結果

SELECT * 
FROM @T 
ORDER BY ID; 

+----+-----------+----------+---------+---------+---------+ 
| id | FirstName | LastName | HouseNo | MyCount | CountId | 
+----+-----------+----------+---------+---------+---------+ 
| 1 | Imran  | Khan  | 1-1  |  3 |  1 | 
| 2 | Waseem | Khan  | 1-1  |  3 |  1 | 
| 3 | Rihan  | Khan  | 1-1  |  3 |  1 | 
| 4 | Moiz  | Shaikh | 1-2  |  3 |  2 | 
| 5 | Zbair  | Shaikh | 1-2  |  3 |  2 | 
| 6 | Sultan | Shaikh | 1-2  |  3 |  2 | 
| 7 | Zaid  | Khan  | NULL |  1 |  3 | 
| 10 | Parvez | Patel | 1-3  |  2 |  4 | 
| 11 | Ahmed  | Patel | 1-3  |  2 |  4 | 
| 12 | Rahat  | Syed  | 1-4  |  1 |  5 | 
| 13 | Talha  | Khan  | NULL |  2 |  6 | 
| 14 | Zia  | Khan  | NULL |  2 |  6 | 
| 15 | Arshad | Patel | 1-3  |  2 |  7 | 
| 16 | Samad  | Patel | 1-3  |  2 |  7 | 
| 17 | Raees  | Syed  | 1-4  |  1 |  8 | 
| 18 | Azmat  | Khan  | NULL |  2 |  9 | 
| 19 | Imran  | Khan  | NULL |  2 |  9 | 
+----+-----------+----------+---------+---------+---------+ 
+1

@ImranAliKhan,不客氣。用一組具有代表性的樣本數據和預期結果來理解問題變得容易。 –

1
SELECT COUNT(ID) AS _COUNT 
FROM MYTABLE 
GROUP BY ISNULL(LASTNAME, ''), ISNULL(HOUSENO, ''); 
+0

在回答plz rad問題和期望之前。 –

+0

沒有冒犯,但我回答後編輯了這個問題。 :) –

2

這應該這樣做

declare @temp table (id int, firstname varchar(5), lastname varchar(5), houseno varchar(5), mycount int) 

insert into @temp values(1, 'A', 'C', '1-1', 2) 
insert into @temp values(2, 'B', 'C', '1-1', 2) 
insert into @temp values(4, 'D', 'A', null, 3) 
insert into @temp values(5, 'F', 'A', null, 3) 
insert into @temp values(6, 'J', 'A', null, 3) 
insert into @temp values(7, 'Q', 'X', '1-2', 3) 
insert into @temp values(8, 'D', 'X', '1-2', 3) 
insert into @temp values(9, 'D', 'X', '1-2', 3) 
insert into @temp values(10, 'A', 'C', '1-3', 3) 
insert into @temp values(11, 'B', 'C', '1-3', 3) 
insert into @temp values(12, 'C', 'C', '1-3', 3) 
insert into @temp values(14, 'F', 'K', null, 2) 
insert into @temp values(15, 'J', 'K', null, 2) 
insert into @temp values(16, 'Q', 'X', '1-5', 1) 

select count(ID) as _count 
from @temp 
group by isnull(lastname, ''), isnull(houseno, '') 

這將返回

_count 
    3  
    2  
    2  
    3  
    3  
    1  

可以吐出更多的細節與此:

select distinct 
     t.lastname, 
     isnull(t.houseno, '') as houseno, 
     (select count(ID) from @temp t2 where t2.lastname = t.lastname and t2.houseno = t.houseno) as _count_filled, 
     (select count(ID) from @temp t2 where t2.lastname = t.lastname and isnull(t2.houseno, '') = isnull(t.houseno, '') and t2.houseno is null) as _count_empty 
from @temp t 

會換貨政... RN這樣的:

lastname houseno _count_filled _count_empty  
A     0    3 
C   1-1  2    0 
C   1-3  3    0 
K     0    2 
X   1-2  3    0 
X   1-5  1    0 
+0

與我的回答有什麼不同? –

+0

它不是,我沒有看到你的答案,直到我發佈我的 – GuidoG

1

我相信你的第三個,主要目的,是爲了更新與結果mycount的柱,使各條線上。一般來說,你正在尋找的是相關子查詢

UPDATE MYTABLE T1 
    SET T1.MYCOUNT = 
    (SELECT COUNT (*) 
     FROM MYTABLE T2 
     WHERE T1.LASTNAME = B2.LASTNAME 
     AND NVL (T2.HOUSENO, 0) = NVL (T1.HOUSENO, 0) 
     GROUP BY T2.LASTNAME, T2.HOUSENO); 

*注:這是的Oracle SQL

1

我同意@Vladimir Baranov的分析,所以我不再重複。 我只想讓查詢變得更加簡單,如下

--drop table #temp 
create table  #temp  (id int, firstname varchar(15), lastname varchar(15), houseno varchar(5)); 
go 
insert into #temp (id, firstname, lastname, houseno) 
values 
(1   , 'Imran'       ,'Khan'        ,'1-1')         
,(2   , 'Waseem'      ,'Khan'        ,'1-1')         
,(3   , 'Rihan'       ,'Khan'        ,'1-1')         
,(4   , 'Moiz'        ,'Shaikh'      ,'1-2')         
,(5   , 'Zbair'       ,'Shaikh'      ,'1-2')         
,(6   , 'Sultan'      ,'Shaikh'      ,'1-2')         
,(7   , 'Zaid'        ,'Khan'        , null)         
,(10  , 'Parvez'      ,'Patel'       ,'1-3')         
,(11  , 'Ahmed'       ,'Patel'       ,'1-3')         
,(12  , 'Rahat'       ,'Syed'        ,'1-4')         
,(13  , 'Talha'       ,'Khan'        ,null)         
,(14  , 'Zia'         ,'Khan'        ,null)         
,(15  , 'Arshad'      ,'Patel'       ,'1-3')         
,(16  , 'Samad'       ,'Patel'       ,'1-3')         
,(17  , 'Raees'       ,'Syed'        ,'1-4')         
,(18  , 'Azmat'       ,'Khan'        , null)      
,(19  , 'Imran'       ,'Khan'        , null) 
  
-- query 
; with c as (
select id, firstname, lastname, houseno=isnull(houseno, '') 
, new_id=row_number() over (partition by lastname, isnull(houseno, '') order by id) 
, grp = id -row_number() over (partition by lastname, isnull(houseno, '') order by id) 
FROM #temp 
) 
, d as (
select id, firstname, lastname, houseno, T.cnt, c.grp 
, row_id=id-row_number() over (partition by grp, houseno order by c.grp) 
from c 
cross apply (select cnt=count(*) from c as c2 where c.grp = c2.grp and c.lastname=c2.lastname and c.houseno=c2.houseno) T(cnt) 
) 
select id, FirstName, LastName, Houseno, MyCount=cnt, CountId= DENSE_RANK() over (order by row_id) 
from d 

結果如下(在SQL Server 2012測試):

enter image description here

+1

您的查詢假定'id'沒有空白。例如,將示例數據中的id = 10(Parvez Patel)更改爲8.最終結果將會更改,即使它不應該。在您的查詢中,如果Parvez Patel和Ahmed Patel的ID不是連續的,則不會將它們分組在一起。 –

+2

這的確是我的假設@VladimirBaranov。如果沒有,我所需要做的就是用row_number()替換原始ID(按ID排序)。 – jyao

3

使用CTE,然後更新您的表如下:

;WITH T AS 
(
    SELECT 
     *,  
     ROW_NUMBER() OVER (ORDER BY ID) AS SrNo, 
     ROW_NUMBER() OVER (PARTITION BY LastName,HouseNo ORDER BY HouseNo) AS PartNo   
    FROM MYTABLE 
), 
X as 
(
    SELECT 
     T.LastName, 
     T.HouseNo, 
     (MAX(T.ID)-MIN(T.ID))+1 AS NoOfCount,   
     ROW_NUMBER() OVER(Order BY MAX(ID)) AS RowNo, 
     MAX(ID) AS ID  
    FROM T 
    GROUP BY T.LastName,T.HouseNo, (T.SrNo - T.PartNo)  
) 

Update MYTABLE 
SET 
    MyCount=X.NoOfCount, 
    CountId=X.RowNo 
FROM X 
WHERE MYTABLE.LastName=X.LastName 
AND MYTABLE.HouseNo=X.HouseNo 
AND MYTABLE.ID<=X.ID 

SELECT * FROM MYTABLE 

輸出:

enter image description here

+2

這很有趣,但我認爲它會在ID = 7和ID = 10附近突破,因爲如果LastName和HouseNo在這兩個記錄中相同,則論文值不是連續的。它不需要修改。 –

1

首先創建一個視圖來計算每個零件的計數和等級。

CREATE VIEW cnt AS 
SELECT 
    T.LastName, 
    T.HouseNo, MIN(t.id) AS START , MAX(T.id) AS finish , 
    (MAX(T.ID)-MIN(T.ID))+1 AS NoOfCount,   
    ROW_NUMBER() OVER(Order BY MAX(T.ID)) AS RowNo, 
    MAX(T.ID) AS ID  
FROM (
SELECT 
    *,  
    ROW_NUMBER() OVER (ORDER BY ID) AS SrNo, 
    ROW_NUMBER() OVER (PARTITION BY LastName,HouseNo ORDER BY HouseNo) AS PartNo   
FROM myTable 
) T 
GROUP BY T.LastName,T.HouseNo, (T.SrNo - T.PartNo) 

然後用它爲你的目的:

SELECT a.*, 
     b.NoOfCount, 
     b.RowNo 
FROM myTable   AS a 
     INNER JOIN cnt AS b 
      ON a.id BETWEEN b.start AND b.finish 

這裏是結果:

enter image description here

0

試試這個:

SELECT COUNT(ID)AS _COUNT來自MYTABLE GROUP LASTNAME + ISNULL(HOUSENO,'')