2016-10-04 253 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,'')