TSQL:按一列分组,计算所有行,并根据row_number将值保留在第二列上

时间:2020-09-30 10:52:08

标签: sql-server tsql sql-server-2008

我有一个查询,它根据一些规则返回一个ID,一个名称和Row_Number()。

查询看起来像这样

SELECT 
    tm.id AS Id,
    pn.Name AS Name,
    ROW_NUMBER() OVER(PARTITION BY tm.id ORDER BY tm.CreatedDate ASC) AS Row
FROM 
    #tempTable AS tm
LEFT JOIN 
    names pn WITH (NOLOCK) ON tm.nameId = pn.NameId
WHERE ....

上面查询的输出看起来像下面带有伪数据的表

CREATE TABLE people
(
    id int,
    name varchar(55),
    row int
);

INSERT INTO people 
VALUES (1, 'John', 1), (1, 'John', 2), (2, 'Mary', 1),
       (3, 'Jeff', 1), (4, 'Bill', 1), (4, 'Bill', 2),
       (4, 'Bill', 3), (4, 'Billy', 4), (5, 'Bobby', 1),
       (5, 'Bob', 2), (5, 'Bob' , 3), (5, 'Bob' , 4);

我想做的是按id字段分组,计算所有行,但对于名称,请使用带有row = 1的行

我的尝试是这样的,但是很显然,由于在分组依据中包含了x.name,因此我得到了不同的行。

SELECT 
    x.id,
    x.name,
    COUNT(*) AS Value
FROM
    (SELECT 
         tm.id AS Id,
         pn.Name  AS Name,
         ROW_NUMBER() OVER(PARTITION BY tm.id ORDER BY tm.CreatedDate ASC) AS Row
     FROM 
         #tempTable AS tm
     LEFT JOIN 
         names pn WITH (NOLOCK) ON tm.nameId = pn.NameId
     WHERE ....
) x
GROUP BY 
    x.id, x.name
ORDER BY 
    COUNT(*) DESC

虚拟数据的预期结果是:

id    name   count
------------------
 1    John     2
 2    Mary     1
 3    Jeff     1
 4    Bill     4
 5    Bobby    4

2 个答案:

答案 0 :(得分:2)

您可以使用[...] building step above [...] FROM jboss/wildfly:20.0.1.Final USER root RUN yum -y install zip wget && yum clean all RUN sed -i 's/echo " JAVA_OPTS/echo " DB_CONNECTION_URL: $DB_CONNECTION_URL JAVA_OPTS/g' /opt/jboss/wildfly/bin/standalone.sh && \ cat /opt/jboss/wildfly/bin/standalone.sh RUN sed -i 's/<spec-descriptor-property-replacement>false<\/spec-descriptor-property-replacement>/<spec-descriptor-property-replacement>true<\/spec-descriptor-property-replacement><jboss-descriptor-property-replacement>true<\/jboss-descriptor-property-replacement><annotation-property-replacement>true<\/annotation-property-replacement>/g' /opt/jboss/wildfly/standalone/configuration/standalone.xml USER jboss COPY --from=0 /_build/dbt-datasource.ear /opt/jboss/wildfly/standalone/deployments/ ADD target/dbt.war /opt/jboss/wildfly/standalone/deployments/ 窗口函数获取行号= 1的行名,而使用关键字DISTINCT则不需要arr

FIRST_VALUE()

如果您不能使用GROUP BY,则可以使用条件聚合来实现:

SELECT DISTINCT tm.id AS Id
     , FIRST_VALUE(pn.Name) OVER (PARTITION BY tm.id ORDER BY tm.CreatedDate ASC) AS Name
     , COUNT(*) OVER (PARTITION BY tm.id) AS counter
FROM #tempTable AS tm
LEFT JOIN names pn WITH (NOLOCK) ON tm.nameId = pn.NameId
WHERE ....

答案 1 :(得分:1)

这可能是解决您的问题的一种方法:同时对id和目标名称(case when p.row = 1 then p.name end)进行分组。将with rollup添加到分组将“汇总”计数汇总。然后可以使用id上的另一种聚合来合并中间数据集(在小提琴中可见)中的行值。

with cte as
(
  select p.id,
         case when p.row = 1 then p.name end as name,
         count(1) as cnt
  from people p
  group by p.id, case when p.row = 1 then p.name end with rollup
  having grouping(p.id) = 0
)
select cte.id,
       max(cte.name) as name,
       max(cte.cnt) as [count]
from cte
group by cte.id;

Fiddle


这将是另一种解决方案:对id进行分组以进行常规计数查询,然后使用cross apply获取所需的名称。

with cte as
(
  select p.id,
         count(1) as cnt
  from people p
  group by p.id
)
select cte.id,
       n.name,
       cte.cnt as [count]
from cte
cross apply ( select p.name
              from people p
              where p.id = cte.id
                and p.row = 1 ) n;

Fiddle