Sql server 如何从EAV数据模型中检索多个项目及其所有属性?

Sql server 如何从EAV数据模型中检索多个项目及其所有属性?,sql-server,stored-procedures,entity-attribute-value,Sql Server,Stored Procedures,Entity Attribute Value,如何检索多个产品及其所有属性,这些产品的ID以逗号分隔的列表形式传递给存储过程 桌子以简单的EAV方式设计,如下所示: tbl_products id title tbl_product_attributes product_FK attribute_FK attribute_value tbl_attributes id title 以下存储过程仅对一种产品执行此操作: CREATE PROCEDURE get_product @product_id NV

如何检索多个产品及其所有属性,这些产品的ID以逗号分隔的列表形式传递给存储过程

桌子以简单的EAV方式设计,如下所示:

tbl_products
  id
  title

tbl_product_attributes
  product_FK
  attribute_FK
  attribute_value

tbl_attributes
  id
  title
以下存储过程仅对一种产品执行此操作:

CREATE PROCEDURE get_product
  @product_id NVARCHAR(MAX)
AS
  BEGIN
    -- Create a temp table to store values of get_product_attributes sp
    CREATE TABLE #temp ( attributes NVARCHAR(MAX) );

    -- Insert results of get_product_attributes sp into temp table
    INSERT INTO #temp (attributes)
    EXEC get_product_attributes @product_id;

    -- Select product with all its attributes
    SELECT id,
           title,
           ( SELECT attributes FROM #temp ) AS attributes
    FROM   tbl_products
    WHERE  id = @product_id;
  END;
但是,如果我们需要多个产品详细信息(给定产品ID),该怎么办

get_product_attributes存储过程以json形式返回特定产品的所有属性及其值它使用动态sql检索所有属性,然后以json形式返回它们;与此答案的动态sql部分的功能完全相同:


同样使用sql server 2016,可以访问函数并可以轻松地将传递的ID转换为行

一般来说,循环在sql中是不好的。对于你所描述的,我无法想象为什么它会保证一个循环。然而,这里有一个基于集合的方法,它具有简单的连接,除了一个过程之外,它可以消除一切

declare @tbl_products table (
                            id int, 
                            title varchar(16))

insert into @tbl_products
values
(1,'prod1'),
(2,'prod2'),
(3,'prod3'),
(4,'prod4'),
(5,'prod5')

declare @tbl_attributes table (
                                id int,
                                title varchar(16))

insert into @tbl_attributes
values
(1,'attr1'),
(2,'attr2'),
(3,'attr3'),
(4,'attr4'),
(5,'attr5')


declare @tbl_product_attributes table (
                                        product_FK int,
                                        attribute_FK int,
                                        attribute_value varchar(64))

insert into @tbl_product_attributes
values
(1,5,'blah'),
(1,3,'blah blah'),
(2,1,'not sure'),
(2,3,'what should be here'),
(2,4,'but here is a'),
(3,5,'line of text'),
(3,4,'as a place holder')




declare @product_id nvarchar(4000)
set @product_id = '1,3'



if object_id ('tempdb..#staging') is not null
drop table #staging

select
    prod.id
    ,prod.title as ProductTitle
    ,'Attr' + cast(attr.id as char(8)) as AttributeID
    ,attr.title as AttributeTitle
    ,prodAttributes.attribute_value as EAV_AttributeValue
into #staging
from
    @tbl_products prod
inner join
    @tbl_product_attributes prodAttributes
    on prodAttributes.product_FK = prod.id
inner join
    @tbl_attributes attr on
    attr.id = prodAttributes.attribute_FK
inner join
    string_split(@product_id,',') x
    on x.value = prod.id




DECLARE @DynamicPivotQuery AS NVARCHAR(MAX)
DECLARE @ColumnName AS NVARCHAR(MAX)

--Get distinct values of the PIVOT Column 
SELECT @ColumnName= ISNULL(@ColumnName + ',','') 
       + QUOTENAME(AttributeID)
FROM (SELECT DISTINCT AttributeID FROM #staging) AS AttributeID


--Prepare the PIVOT query using the dynamic 
SET @DynamicPivotQuery = 
  N'
    SELECT ProductTitle,  ' + @ColumnName + '
    FROM #staging
    PIVOT(min(AttributeTitle) 
          FOR AttributeID IN (' + @ColumnName + ')) AS PVTTable'
--Execute the Dynamic Pivot Query
EXEC sp_executesql @DynamicPivotQuery
因此,您只需在顶部创建进程

注意:这也可以作为一个连接写得更清楚


您的最后一句话就是您的解决方案…您将加入函数结果。看看下面的图片others@scsimon,当然,我可以在SELECT value from STRING中编写where子句,如where id_SPLIT@product_id, ','; 但是属性部分呢。我认为我应该循环获取产品属性,但由于我使用id的guid,我在使用while循环时遇到了问题,我认为我的最佳选择可能是使用游标和循环获取产品过程来传递每个id。还有其他的吗?!好吧,但应用层需要更干净的输出;id、标题、属性1、属性2。。。并将其值放入行中。所以我需要将属性/值行转换为列,由于每个产品的属性动态性,我可以在存储过程中使用动态sql,而不是在函数中使用。在连接或交叉应用程序或其他情况下,使用存储过程值并不是那么简单的函数。所以我先把它们放在一张桌子里,然后用它。但每次它都返回相同的属性,这是显而易见的,因为每次它只是在临时表中插入First product的属性。似乎按照上述格式检索所有产品属性在某种程度上是复杂的。如果您需要将其导出,则有一个pivot函数。我仍然不会使用动态sql或循环。。。我不知道你所说的使用存储过程值的意思,在连接、交叉应用程序或其他情况下,函数并不是那么简单。但我几乎可以肯定你把这个问题复杂化了。在处理SQL时,必须考虑基于集合的问题。在Java或Py中如何解决问题在这里有很大不同。您的原始代码看起来像是这样想的。。创建类和函数来完成小部分工作。这是一个坏主意。那么你能用pivot部分更新你的答案并告诉我们如何将传递的产品的每个属性检索到列中吗?!Tanx先生,虽然我们最终还是使用了动态sql,但您为我指明了正确的方向。经过一番小小的搜索,我现在完全相信基于集合的方法,并将在编写SQL时尝试以这种方式思考。
create proc yourProc(@product_id nvarchar(4000))
as

select
    prod.id
    ,prod.title as ProductTitle
    ,attr.title as AttributeTitle
    ,prodAttributes.attribute_value as EAV_AttributeValue
from
    @tbl_products prod
inner join
    @tbl_product_attributes prodAttributes
    on prodAttributes.product_FK = prod.id
inner join
    @tbl_attributes attr on
    attr.id = prodAttributes.attribute_FK
where
    prod.id in (select * from string_split(@product_id,','))
select
    prod.id
    ,prod.title as ProductTitle
    ,attr.title as AttributeTitle
    ,prodAttributes.attribute_value as EAV_AttributeValue
from
    @tbl_products prod
inner join
    @tbl_product_attributes prodAttributes
    on prodAttributes.product_FK = prod.id
inner join
    @tbl_attributes attr on
    attr.id = prodAttributes.attribute_FK
inner join
    string_split(@product_id,',') x
    on x.value = prod.id