2016-10-04 6 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 

С учетом указанных выше данных, я хочу взять количество записей с одинаковым HouseNo и LastName.

Для этого я использую

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

но выше утверждение имеет один вопрос. В данных некоторых записей нет HouseNo. В примере выше ID 4,5,6 и 14,15 нет HouseNo. Таким образом, вышеупомянутое утверждение возвращает 5, но оно должно возвращать 3 и 2 отдельно.

Главная цель

  1. Возьмите подсчет, основанный на LastName и HouseNo
  2. Возьмите количество тех записей, которые не имеют HouseNo (Они будут поставляется в серии).
  3. Предстоящий Количество должно быть обновлено в MyCount

Как получить этот счет?

Редактировать Для Bounty:

Примеры данных

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. В выборочных данных MyCount и CountId являются пустыми и должны быть заполнены.
  2. MyCount будет основываться на HouseNo и LastName см ID 1 до 3, его фамилия хана с домом нет 1-1, так что MyCount удостоверения личности 1 до 3 будет 3, и CountId будет 1.
  3. В образце данных есть много записей, которые не имеют HouseNo, поэтому для этого случая будет считаться одинаковая фамилия в серии. Пожалуйста, см. ID 7, его счет будет 1. См. Также ID 18 и 19, его количество будет 2.
  4. CountId - это серийный номер идентификатора. Пожалуйста, см. ID от 1 до 3, это 1 из-за того же дома нет и той же фамилии.
+0

Вы группируете LASTNAME, HOUSENO. A/NULL и K/NULL - это, очевидно, две разные группы, поэтому я не вижу, как ваш запрос может дать вам объединенный счет 5. Не могли бы вы «SELECT LASTNAME, HOUSENO, COUNT (ID)» вместо «SELECT» COUNT (ID) ', чтобы посмотреть, какая группа получает счет 5? –

+0

Я только что проверил. Ваш запрос - кроме опечатки GRUOP/GROUP делает * not * возвращает 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); 

ВЫБРАТЬ запрос

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. Последовательность rn1 перезапускается для каждого LastName, HouseNo. Он разделен на LastName, HouseNo. rn2 представляет собой простую увеличивающуюся последовательность без зазоров. Нам это нужно, потому что оригинал ID определяет порядок, но может иметь пробелы.

Затем мы вычитаем эти две последовательности и разность дает нам GroupNumber.

Подсчет количества элементов в группе прост COUNT, что дает нам NewMyCount.

Перечисление групп с последовательными номерами без пробелов осуществляется в два этапа. Сначала MIN дает идентификатор для группы, то DENSE_RANK генерирует последовательность NewCountId без пробелов.


Если вы действительно хотите обновить исходную таблицу с рассчитанной NewMyCount и NewCountId, легко превратить 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 

будет RETU гп это:

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

Согласен с анализом Владимира Баранова, поэтому я не буду здесь повторять. Я просто хочу, чтобы сделать запрос немного проще, так как следующее (проверено в SQL Server 2012)

--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 

Результат выглядит следующим образом:

enter image description here

+1

Ваш запрос предполагает, что 'id' не имеет пробелов. Например, измените id = 10 (Parvez Patel) в образцах данных до 8. Конечный результат изменится, хотя он не должен. В вашем запросе 'Parvez Patel' и' Ahmed Patel' не будут сгруппированы, если их идентификаторы не являются последовательными. –

+2

Это действительно мое предположение @ Владимира Баранова. Если это не так, все, что мне нужно сделать, это заменить исходный идентификатор на row_number() (по порядку по ID). – jyao

3

Использование КТР, а затем обновить ваш таблица, как показано ниже:

;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, '')