请教一个查询,有点难度哦!(附脚本)
脚本如下:
USE [AdventureWorks]
GO
/****** Object: Table [dbo].[Table_1] Script Date: 2012/11/3 3:13:29 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[Table_1](
[id] [bigint] IDENTITY(1,1) NOT NULL,
[类别名称] [varchar](50) NULL,
[方式] [varchar](50) NULL,
[名称] [varchar](50) NULL,
[值] [varchar](50) NULL,
CONSTRAINT [PK_Table_1] PRIMARY KEY CLUSTERED
(
[id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_PADDING ON
GO
/****** Object: Table [dbo].[Table_2] Script Date: 2012/11/3 3:13:30 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[Table_2](
[id] [bigint] IDENTITY(1,1) NOT NULL,
[Table_1_ID] [bigint] NULL,
[Property] [varchar](50) NULL,
CONSTRAINT [PK_Table_2] PRIMARY KEY CLUSTERED
(
[id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_PADDING ON
GO
/****** Object: Table [dbo].[Table_3] Script Date: 2012/11/3 3:13:30 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[Table_3](
[id] [bigint] IDENTITY(1,1) NOT NULL,
[产品名称] [varchar](50) NULL,
[类别] [varchar](50) NULL,
CONSTRAINT [PK_Table_3] PRIMARY KEY CLUSTERED
(
[id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_PADDING ON
GO
SET IDENTITY_INSERT [dbo].[Table_1] ON
INSERT [dbo].[Table_1] ([id], [类别名称], [方式], [名称], [值]) VALUES (1, N'食品', N'文本', N'生产日期', N'2012-10-01')
INSERT [dbo].[Table_1] ([id], [类别名称], [方式], [名称], [值]) VALUES (2, N'食品', N'选择', N'状态', N'1')
INSERT [dbo].[Table_1] ([id], [类别名称], [方式], [名称], [值]) VALUES (3, N'食品', N'文本', N'保质期', N'90')
INSERT [dbo].[Table_1] ([id], [类别名称], [方式], [名称], [值]) VALUES (4, N'电器', N'选择', N'状态', N'3')
INSERT [dbo].[Table_1] ([id], [类别名称], [方式], [名称], [值]) VALUES (5, N'电器', N'文本', N'出厂日期', N'2012-09-05')
SET IDENTITY_INSERT [dbo].[Table_1] OFF
SET IDENTITY_INSERT [dbo].[Table_2] ON
INSERT [dbo].[Table_2] ([id], [Table_1_ID], [Property]) VALUES (1, 2, N'正常')
INSERT [dbo].[Table_2] ([id], [Table_1_ID], [Property]) VALUES (2, 2, N'异常')
INSERT [dbo].[Table_2] ([id], [Table_1_ID], [Property]) VALUES (3, 4, N'损坏')
INSERT [dbo].[Table_2] ([id], [Table_1_ID], [Property]) VALUES (4, 4, N'进水')
SET IDENTITY_INSERT [dbo].[Table_2] OFF
SET IDENTITY_INSERT [dbo].[Table_3] ON
INSERT [dbo].[Table_3] ([id], [产品名称], [类别]) VALUES (1, N'喔喔奶糖', N'食品')
INSERT [dbo].[Table_3] ([id], [产品名称], [类别]) VALUES (2, N'喜之郎果冻', N'食品')
INSERT [dbo].[Table_3] ([id], [产品名称], [类别]) VALUES (3, N'新飞冰箱', N'电器')
INSERT [dbo].[Table_3] ([id], [产品名称], [类别]) VALUES (4, N'耐克运动鞋', N'')
SET IDENTITY_INSERT [dbo].[Table_3] OFF
select
x.产品名称,
case when x.类别 is null or ltrim(rtrim(x.类别)) = '' then '无' else x.类别 end as 类别,
isnull(stuff(y.属性,len(y.属性),1,''),'无') as 属性
from table_3 x left join
(
select
distinct a.类别名称,
(
select
b.名称 + ':' +
case when b.方式 = '选择' then ( select c.property from table_2 c where c.id = b.值 AND c.table_1_id = b.id ) else b.值 end,
','
from table_1 b where b.类别名称 = a.类别名称 FOR XML PATH('')
) as 属性
from table_1 a
) y on x.类别 = y.类别名称
产品名称 类别 属性
---------- ------- ---------------------------------------
喔喔奶糖食品生产日期:2012-10-01,状态:正常,保质期:90
喜之郎果冻食品生产日期:2012-10-01,状态:正常,保质期:90
新飞冰箱电器状态:损坏,出厂日期:2012-09-05
耐克运动鞋无无
(4 行受影响)
;WITH c1 as
(SELECT
t1.id
,t1.类别名称
,t1.方式
,t1.名称
,t2.Property
FROM table_1 t1
INNER JOIN table_2 t2 ON t1.值 = t2.id
WHERE 方式 = '选择')
,t1 as
(
SELECT table_3.id,
table_3.产品名称,
table_3.类别,
table_1.名称 + ':' + table_1.值 属性
FROM table_3
LEFT JOIN table_1 on table_1.类别名称 = table_3.类别
WHERE table_1.id not in ( select id from c1 )
UNION ALL
select table_3.id,
table_3.产品名称,
table_3.类别,
c1.名称 + ':' + c1.Property 属性
from table_3
left join c1 on c1.类别名称 = table_3.类别
)
SELECT DISTINCT
CAST(产品名称 AS VARCHAR(8)) 产品名称
,CASE LTRIM(类别) WHEN '' THEN NULL ELSE 类别 END 类别
,STUFF( (SELECT ';'+LTRIM(属性)
FROM t1
WHERE 类别 = d.类别 and 产品名称 = d.产品名称 FOR XML PATH('')),1,1,'' ) 组合属性
from t1 d
order by 产品名称
测试结果:
产品名称 类别 组合属性
-------- --------------- ------------------------------------
耐克运动 NULL NULL
喔喔奶糖 食品 生产日期:2012-10-01;保质期:90;状态:正常
喜之郎果 食品 生产日期:2012-10-01;保质期:90;状态:正常
新飞冰箱 电器 出厂日期:2012-09-05;状态:损坏
(4 行受影响)
[其他解释]
该回复于2012-11-05 14:31:52被管理员删除
[其他解释]
该回复于2012-11-05 14:31:52被管理员删除
[其他解释]
我只是想了解 那个Not In 运算导致的性能下降有多大,了解之后再进行改进即可,我一直认为平行查询性能不应该比子查询低很多,呵呵……
[其他解释]
with 的话,几万数据性能也不会很差,我试过,不过not in的话,由于大部分情况下会造成表扫描,所以如果可以,就少用。不过由于with的临时集合不能创建索引,所以在非常大的数据量,如百万甚至千万的时候,速度会明显下降,这个时候可以考虑使用具有索引的临时表来替代,表变量只能创建主键约束,所以这个也要按照数据量来评估是否有必要使用表变量。