Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/67.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 获取每组的前5项记录,并将它们按组排列成一行_Sql_Sql Server_String_Common Table Expression - Fatal编程技术网

Sql 获取每组的前5项记录,并将它们按组排列成一行

Sql 获取每组的前5项记录,并将它们按组排列成一行,sql,sql-server,string,common-table-expression,Sql,Sql Server,String,Common Table Expression,我有一个表联系人,基本上如下所示: Id | Name | ContactId | Contact | Amount --------------------------------------------- 1 | A | 1 | 12323432 | 555 --------------------------------------------- 1 | A | 2 | 23432434 | 349 ------------

我有一个表联系人,基本上如下所示:

Id | Name | ContactId |  Contact   | Amount
---------------------------------------------
1  |  A   |     1     | 12323432   |  555
---------------------------------------------
1  |  A   |     2     | 23432434   |  349
---------------------------------------------
2  |  B   |     3     | 98867665   |  297
--------------------------------------------
2  |  B   |     4     | 88867662   |  142
--------------------------------------------
2  |  B   |     5     |   null     |  698
--------------------------------------------
这里,ContactId在整个表中是唯一的。联系人可以为空&我想排除这些联系人

现在,我想根据他们的数量为每个Id选择前5位联系人。我通过以下查询完成了这一点:

 WITH cte AS (
    SELECT id, Contact, amount, ROW_NUMBER() 
    over (
        PARTITION BY id
        order by amount desc
    ) AS RowNo 
    FROM contacts
    where contact is not null
)
select *from cte where RowNo <= 5
我使用以下查询来实现这一点,但它仍然在单独的行中提供所有记录,还包括空值:

WITH cte AS (
    SELECT id, Contact, amount,contactid, ROW_NUMBER() 
    over (
        PARTITION BY id
        order by amount desc
    ) AS RowNo 
    FROM contacts
    where contact is not null
)
select *from id, name, 
STUFF ((
          SELECT distinct  '; ' + isnull(contact,'')   FROM cte 
          WHERE co.id= cte.id and co.contactid= cte.contactid
          and RowNo <= 5
 FOR XML PATH('')),1, 1, '')as contact
 from contacts co inner join cte where cte.id = co.id and co.contactid= cte.contactid
上面的查询仍然为我提供了不同行中的前5名联系人&也包括null


把CTE和其他东西一起使用是个好主意吗?请建议是否有比此更好的方法。

如果您运行的是SQL Server 2017或更高版本,您可以使用string\u agg:与大多数其他聚合函数一样,它通过设计忽略空值

select id, name, string_agg(contact, ',') within group (order by rn) all_contacts
from (
    select id, name, contact
        row_number() over (partition by id order by amount desc) as rn 
    from contacts
    where contact is not null
) t
where rn <= 5
group by id, name

如果您运行的是SQL Server 2017或更高版本,则可以使用string_agg:作为大多数其他聚合函数,它通过设计忽略空值

select id, name, string_agg(contact, ',') within group (order by rn) all_contacts
from (
    select id, name, contact
        row_number() over (partition by id order by amount desc) as rn 
    from contacts
    where contact is not null
) t
where rn <= 5
group by id, name

我的最后一个问题是:

在我的最终选择中,我不需要原始的联系人表,因为我已经在CTE中拥有了我所需要的一切。另外,在内部,我使用contactid加入,这就是我在这里要做的。因为我将该条件用于连接,所以我将获得不同行中的记录。我已经删除了这两个条件,它的工作

WITH cte AS (
    SELECT id, Contact, amount,contactid, ROW_NUMBER() 
    over (
        PARTITION BY id
        order by amount desc
    ) AS RowNo 
    FROM contacts
    where contact is not null
)
select *from id, name, 
STUFF ((
          SELECT distinct  '; ' + isnull(contact,'')   FROM cte 
          WHERE co.id= cte.id              
          and RowNo <= 5
 FOR XML PATH('')),1, 1, '')as contact
 from  cte where rowno <= 5

我的最后一个问题是:

在我的最终选择中,我不需要原始的联系人表,因为我已经在CTE中拥有了我所需要的一切。另外,在内部,我使用contactid加入,这就是我在这里要做的。因为我将该条件用于连接,所以我将获得不同行中的记录。我已经删除了这两个条件,它的工作

WITH cte AS (
    SELECT id, Contact, amount,contactid, ROW_NUMBER() 
    over (
        PARTITION BY id
        order by amount desc
    ) AS RowNo 
    FROM contacts
    where contact is not null
)
select *from id, name, 
STUFF ((
          SELECT distinct  '; ' + isnull(contact,'')   FROM cte 
          WHERE co.id= cte.id              
          and RowNo <= 5
 FOR XML PATH('')),1, 1, '')as contact
 from  cte where rowno <= 5

您可以使用条件聚合: 身份证,姓名,联系人

select id, name,
       concat(max(case when seqnum = 1 then contact + ';' end),
              max(case when seqnum = 2 then contact + ';' end),
              max(case when seqnum = 3 then contact + ';' end),
              max(case when seqnum = 4 then contact + ';' end),
              max(case when seqnum = 5 then contact + ';' end)
             ) as contacts              
from (select c.*
             row_number() over (partition by id order by amount desc) as seqnum
      from contacts c
      where contact is not null
     ) c
group by id, name;

您可以使用条件聚合: 身份证,姓名,联系人

select id, name,
       concat(max(case when seqnum = 1 then contact + ';' end),
              max(case when seqnum = 2 then contact + ';' end),
              max(case when seqnum = 3 then contact + ';' end),
              max(case when seqnum = 4 then contact + ';' end),
              max(case when seqnum = 5 then contact + ';' end)
             ) as contacts              
from (select c.*
             row_number() over (partition by id order by amount desc) as seqnum
      from contacts c
      where contact is not null
     ) c
group by id, name;

我同意@GMB。字符串是你需要的

WITH
contacts(Id,nm,ContactId,Contact,Amount) AS (
          SELECT 1,'A',1,12323432,555
UNION ALL SELECT 1,'A',2,23432434,349
UNION ALL SELECT 2,'B',3,98867665,297
UNION ALL SELECT 2,'B',4,88867662,142
UNION ALL SELECT 2,'B',5,NULL    ,698
)
,
with_filter_val AS (
  SELECT
    *
  , ROW_NUMBER() OVER(PARTITION BY id ORDER BY amount DESC) AS rn
  FROM contacts
)
SELECT
  id
, nm
, STRING_AGG(CAST(contact AS CHAR(8)),',') AS contact_list
FROM with_filter_val
WHERE rn <=5
GROUP BY
  id
, nm
-- out  id | nm |   contact_list    
-- out ----+----+-------------------
-- out   1 | A  | 12323432,23432434
-- out   2 | B  | 98867665,88867662

我同意@GMB。字符串是你需要的

WITH
contacts(Id,nm,ContactId,Contact,Amount) AS (
          SELECT 1,'A',1,12323432,555
UNION ALL SELECT 1,'A',2,23432434,349
UNION ALL SELECT 2,'B',3,98867665,297
UNION ALL SELECT 2,'B',4,88867662,142
UNION ALL SELECT 2,'B',5,NULL    ,698
)
,
with_filter_val AS (
  SELECT
    *
  , ROW_NUMBER() OVER(PARTITION BY id ORDER BY amount DESC) AS rn
  FROM contacts
)
SELECT
  id
, nm
, STRING_AGG(CAST(contact AS CHAR(8)),',') AS contact_list
FROM with_filter_val
WHERE rn <=5
GROUP BY
  id
, nm
-- out  id | nm |   contact_list    
-- out ----+----+-------------------
-- out   1 | A  | 12323432,23432434
-- out   2 | B  | 98867665,88867662

谢谢,但我认为我们使用的是SQL Server 2012或更低版本。是的。我尝试了不同的事情,得到了同样的问题并发布了同样的帖子。您的回答似乎也是正确的,但我认为您不需要分组。谢谢,但我认为我们使用的是SQL Server 2012或更低版本。是的。我尝试了不同的事情,得到了同样的问题并发布了同样的帖子。你的答案似乎也是正确的,但我认为你不需要在那里分组。我知道这一点,但正如我在评论中提到的,如果我可以使用像String_Split和String_Agg这样的函数,生活会容易得多。谢谢你的回答。如果你不需要在这个过程中添加排名/前n名的评估…我知道这一点,但正如我在评论中提到的,如果我可以使用像String_Split和String_Agg这样的函数,生活会容易得多。谢谢您的回答。如果您需要在过程中添加排名/前n名评估,则不需要。。。