如何通过主键将元数据附加到分组选择

How to append metadata to a grouped selection by primary key

我有一个收藏夹列表,例如:

示例数据

| key | item_id | list_name |  customer_id |meta           |
|-----|---------|-----------|--------------|---------------|
| 1   | A-11    | aa11      | 001          | unique-data-1 |
| 2   | A-11    | bb22      | 001          | unique-data-2 |
| 3   | A-26    | cc33      | 001          | unique-data-3 |
| 4   | A-28    | aa11      | 002          | unique-data-4 |
| 5   | J-52    | aa11      | 001          | unique-data-5 |
| 6   | X-53    | aa11      | 001          | unique-data-6 |

期望输出

对于@item_id nvarchar(20) = 'A-11'

| key | isFavorited | list_name | meta          |
|-----|-------------|-----------|---------------|
| 1   | Y           | aa11      | unique-data-1 | 
| 2   | Y           | bb22      | unique-data-2 |
| 3   | N           | cc33      | unique-data-3 |

并且想return select所有可用列表的离子,以及特定项目是否是该列表的一部分,及其元数据。

declare @item_id nvarchar(20) = 'A-11'
declare @customer_id nvarchar(20) = 001

select
[key],
[isFavorited] = max(case when [item_id] = @item_id then 'Y' else 'N' end)
[list_name]
[meta]
from favorites
where customer_id = @customer_id
group by [list_name], [key], [meta]

尝试各种方法时出现的问题:

  1. 我遇到的问题是,由于 meta 是唯一的,分组依据破坏了 select

  2. 的唯一性
  3. 像下面这样的交叉应用不会根据匹配的 key.

    应用正确的 meta
    cross apply (
      select top 1 
      [meta]
      from favorites
       where customer_id = @customer_id
    )
    
  4. 当按行号 select 时,要加入的实际 key 丢失了,所以我无法加入 meta

    "noRow" = row_number() over(order by h_po_no asc)
    

我愿意

  1. 传入一个item_idcustomer_id
  2. Return 该客户的所有列表
  3. 获取传入的每个列表的收藏状态item_id
    • 如果某项与给定的 customer_id customer_id
    • 匹配 list_nameitem_id,则该项目被标记为收藏
  4. 获取主要行 keymeta 数据

我怎样才能 return select 一个 list_nameisFavorite 状态、key 的独特 select 离子,并且它是 meta

要return 所需的输出,您根本不需要任何聚合。一个简单的 case 表达式和一个 where 子句就可以做到这一点。

declare @Favorites table
(
    MyKey int
    , item_id varchar(10)
    , list_name varchar(10)
    , customer_id varchar(10)
    , meta varchar(20)
)
insert @Favorites values
(1, 'A-1', 'list-1', '001', 'unique-data-1')
, (2, 'A-1', 'list-2', '001', 'unique-data-2')
, (3, 'A-2', 'list-3', '001', 'unique-data-3')
, (4, 'A-2', 'list-1', '002', 'unique-data-1')

select *
from @Favorites

declare @item_id nvarchar(20) = 'A-1'
    , @customer_id nvarchar(20) = '001'

select f.MyKey
    , isFavorited = case when f.item_id = @item_id then 'Y' else 'N' end
    , listName = f.list_name
    , f.meta
from favorites f
where f.customer_id = @customer_id
order by f.MyKey

测试参数

declare @item_id nvarchar(20) = 'A-11'
declare @customer_id nvarchar(20) = 001

解决方案

drop table if exists #tmp

;with cte as (
  select
  [key],
  [list_name],
  [rn] = row_number() over (partition by list_name order by list_name desc)
  from favorites
  where customer_id = @customer_id
  group by [list_name], [key], [meta]
)
select *
into #tmp
from cte
where [rn] = 1

select 
[i],
[json],
#t.[tmp]
from #tmp #t
inner join (
  select
  [isFavorited] = max(case when [item_id] = @item_id then 'Y' else 'N' end)
  [list_name]
  from favorites
  where customer_id = @customer_id
  group by [list_name]
) j 
on j.list_name = #t.list_name