【问题标题】:How to get ProductIds by multi-property search in sql or Linq To Sql?如何通过 sql 或 Linq To Sql 中的多属性搜索获取 ProductIds?
【发布时间】:2011-06-27 03:50:59
【问题描述】:

有两个表:ProductProductProperty

ProductProperty 是一个存储产品的InfoKeyInfoValue 的表。

SQL 示例脚本是:

CREATE TABLE [dbo].[ProductProperty](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [ProductId] [int] NOT NULL,
    [InfoKey] [nvarchar](50) COLLATE Chinese_PRC_CI_AS NOT NULL,
    [InfoValue] [nvarchar](50) COLLATE Chinese_PRC_CI_AS NOT NULL,
 CONSTRAINT [PK_ProductProperty] PRIMARY KEY CLUSTERED 
(
    [Id] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON)
)

GO

SET IDENTITY_INSERT [dbo].[ProductProperty] ON
INSERT [dbo].[ProductProperty] ([Id], [ProductId], [InfoKey], [InfoValue]) VALUES (1, 1, N'k1', N'v1')
INSERT [dbo].[ProductProperty] ([Id], [ProductId], [InfoKey], [InfoValue]) VALUES (3, 2, N'k1', N'v1')
INSERT [dbo].[ProductProperty] ([Id], [ProductId], [InfoKey], [InfoValue]) VALUES (4, 3, N'k1', N'v2')
INSERT [dbo].[ProductProperty] ([Id], [ProductId], [InfoKey], [InfoValue]) VALUES (6, 5, N'k1', N'v1')
INSERT [dbo].[ProductProperty] ([Id], [ProductId], [InfoKey], [InfoValue]) VALUES (7, 2, N'k2', N'v1')
INSERT [dbo].[ProductProperty] ([Id], [ProductId], [InfoKey], [InfoValue]) VALUES (8, 1, N'k2', N'v1')
INSERT [dbo].[ProductProperty] ([Id], [ProductId], [InfoKey], [InfoValue]) VALUES (9, 5, N'k2', N'v2')
INSERT [dbo].[ProductProperty] ([Id], [ProductId], [InfoKey], [InfoValue]) VALUES (10, 2, N'k3', N'v2')
INSERT [dbo].[ProductProperty] ([Id], [ProductId], [InfoKey], [InfoValue]) VALUES (11, 3, N'k3', N'v2')
INSERT [dbo].[ProductProperty] ([Id], [ProductId], [InfoKey], [InfoValue]) VALUES (12, 5, N'k3', N'v1')
SET IDENTITY_INSERT [dbo].[ProductProperty] OFF

GO

CREATE TABLE [dbo].[Product](
    [ProductId] [int] IDENTITY(1,1) NOT NULL,
    [ProductName] [nvarchar](50) COLLATE Chinese_PRC_CI_AS NULL,
 CONSTRAINT [PK_Product] PRIMARY KEY CLUSTERED 
(
    [ProductId] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON)
)

GO

SET IDENTITY_INSERT [dbo].[Product] ON
INSERT [dbo].[Product] ([ProductId], [ProductName]) VALUES (1, N'Product_A1')
INSERT [dbo].[Product] ([ProductId], [ProductName]) VALUES (2, N'Product_A2')
INSERT [dbo].[Product] ([ProductId], [ProductName]) VALUES (3, N'Product_B1')
INSERT [dbo].[Product] ([ProductId], [ProductName]) VALUES (4, N'Product_B2')
INSERT [dbo].[Product] ([ProductId], [ProductName]) VALUES (5, N'Product_B3')
SET IDENTITY_INSERT [dbo].[Product] OFF

GO

样本数据:

[Product Table]

ProductId ProductName

1   Product_A1
2   Product_A2
3   Product_B1
4   Product_B2
5   Product_B3


[ProductProperty  Table]

Id ProductId InfoKey InfoValue

1   1   k1  v1
3   2   k1  v1
4   3   k1  v2
6   5   k1  v1
7   2   k2  v1
8   1   k2  v1
9   5   k2  v2
10  2   k3  v2
11  3   k3  v2
12  5   k3  v1

我想获取产品的 ProductProperty k1=v1 和 k2=v1 的 productIds,如下所示:

(InfoKey='k1' AND InfoValue='v1') and (InfoKey='k2' AND InfoValue='v1')

结果应该是:

ProductId
1
2

如何在 Sql 或 LinqToSql 中执行此操作?

【问题讨论】:

  • 您真正需要什么,SQL 还是 LINQ-to-SQL?现在你有两个答案,而且都是正确的,其中一个是 SQL,另一个是 LINQ-to-SQL。你打算怎么选?

标签: c# .net sql sql-server linq-to-sql


【解决方案1】:

如果您正在检查的属性条件的数量是静态的(在本例中为两个),那么您可以实现如下查询。如果没有,请回帖并让我们知道您是否需要更动态(以支持三个、四个等条件)

select  ProductId
from    dbo.productproperty
where   (InfoKey='k1' AND InfoValue='v1') or 
        (InfoKey='k2' AND InfoValue='v1')
group 
by      ProductId 
having  count(*) = 2;

编辑:动态条件计数

;with c_stage (k, v)
as  (   select 'k1', 'v1' union all
        select 'k2', 'v1'
    )
select  ProductId
from    dbo.productproperty pp
join    c_stage t on 
        pp.InfoKey = t.k and 
        pp.InfoValue = t.v
group 
by      ProductId 
having  count(*) = (select count(*) from c_stage);

【讨论】:

  • 这只有在没有重复的情况下才有效,但这是一个公平的假设。
  • 好点亚历克斯。对了。我的动态条件解决方案也是如此。
  • Nathan Skerl,非常感谢。
【解决方案2】:

查询如下所示:

var q = 
    from product in db.Product
    where
        db.ProductProperty.Any(arg => arg.ProductId = product.Id && arg.InfoKey = "k1" && arg.InfoValue = "v1") &&
        db.ProductProperty.Any(arg => arg.ProductId = product.Id && arg.InfoKey = "k2" && arg.InfoValue = "v1")
    select product.Id;

有了这个特殊的条件,它可以被简化成这样:

var q =
    from product in db.Product
    let properties = db.ProductProperty.Where(arg => arg.ProductId = product.Id && arg.InfoValue = "v1")
    where
        properties.Any(arg => arg.InfoKey = "k1") &&
        properties.Any(arg => arg.InfoKey = "k2")
    select product.Id;

如果条件是动态的:

var q =
    from product in db.Product
    select
        new
        {
            Product = product,
            Properties = db.ProductProperty.Where(arg => arg.ProductId = product.Id)
        };

if (something1)
    q = q.Where(arg => arg.InfoKey = "k1" && arg.InfoValue = "v1");
if (something2)
    q = q.Where(arg => arg.InfoKey = "k2" && arg.InfoValue = "v1");

var result = q.Select(arg => new { arg.Product.Id, arg.Product.Name }).ToList();

【讨论】:

  • 如果条件计数未知,可以在Linq To Sql中做吗?
  • @Mike108 - 添加了动态条件。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多