看到SQL版问的最多的问题,每天都是重复的,今天无事,整一下发上.行转列,列分行,行合并列,etc.

fcuandy 2008-01-23 06:13:26
实现的方法还有很多,时间有限,没有一一列出来,新手可以参考一下,不要再发重复贴子了,每点一个"高难度xxx"之类的贴子进去都是这几种.

bom树之类的没有写例子,都差不多.有时间的朋友可以发上来贴上去.
/*=============
===fcuandy=====
===2008.1.23===
=============*/

CREATE TABLE ta(id INT IDENTITY(1,1),cid INT,name VARCHAR(10))
GO
INSERT ta SELECT 1,'a'
UNION ALL SELECT 1,'b'
UNION ALL SELECT 1,'c'
UNION ALL SELECT 2,'d'
UNION ALL SELECT 3,'e'
UNION ALL SELECT 3,'f'
GO

/*
示例 1
同一分类中取1条或n条。
单表及多表的写法
*/

-----------------------------------------------------------
--以ta为例,cid为分类id,每个id取一条,我以取最小id为约束条件
SELECT a.* FROM ta a
WHERE NOT EXISTS(SELECT 1 FROM ta WHERE cid=a.cid AND id<a.id)
SELECT a.* FROM ta a
WHERE 1>(SELECT COUNT(*) FROM ta WHERE cid=a.cid AND id<a.id)

SELECT a.* FROM ta a
WHERE id IN (SELECT TOP 1 ID FROM ta WHERE cid=a.cid ORDER BY id)
SELECT a.* FROM ta a
WHERE id = (SELECT TOP 1 ID FROM ta WHERE cid=a.cid ORDER BY id)
SELECT a.* FROM ta a
WHERE id IN (SELECT MIN(ID) FROM ta WHERE cid=a.cid)
SELECT a.* FROM ta a
WHERE id = (SELECT MIN(ID) FROM ta WHERE cid=a.cid)
SELECT a.*
FROM ta a
INNER JOIN
(SELECT MIN(id) mi FROM ta GROUP BY cid) b
ON id = mi
--etc.其它的组合写法再不累赘

--以cid为分类,每个cid取id最小的2条记录,2可以适当修改
SELECT a.* FROM ta a
WHERE 2>(SELECT COUNT(*) FROM ta WHERE cid=a.cid AND id<a.id)
SELECt a.* FROM ta a
WHERE id IN (SELECT TOP 2 ID FROM ta WHERE cid=a.cid ORDER BY ID)
SELECT a.*
FROM ta a
INNER JOIN
(SELECT ID,CNT=(SELECT COUNT(*) FROM ta WHERE cid=x.cid AND id<x.id) FROM ta x) b
ON a.id = b.id AND cnt<2
--etc.其它的组合写法再不累赘




--上面是针对ta单表。 如果多表,下面以二表为例

CREATE TABLE tb(cid INT,className VARCHAR(10))
GO
INSERT tb SELECT 1,'A'
UNION ALL SELECT 2,'B'
UNION ALL SELECT 3,'C'
GO
--ta,tb以cid关联,取每个cid中id最小的一条记录,需要 tb.className,tb.cid,ta.id,ta.name列。
SELECT b.*,a.*
FROM tb b
INNER JOIN ta a
ON a.cid = b.cid
WHERE NOT EXISTS(SELECT 1 FROM ta WHERE cid=a.cid AND id<a.id)
GO
--多表与单表取数思路一对致,多一次连表操作,可以照上面单表的把其它写法改出来.
--同样,取每个cid中id最小的前n条记录,一样的方法
--需要注意的是连表时,可以用内连,左连,或是老式的多表写法(from ta ,tb where ta.cid=tb.cid默认转换为内连),采用哪种方式依具你的业务需求。



----------------------------------------------------------
/*
示例 2
所谓的多行同组合并
*/

--以ta为例,以cid分组合并,产生如下的数据结果
/*
cid nameS
1 a,b,c
2 d
3 e,f
*/
--函数实现
CREATE FUNCTION myJoinSTR
(
@cid INT
)
RETURNS VARCHAR(1000)
AS
BEGIN
DECLARE @s VARCHAR(1000)
SELECT @s=ISNULL(@s+',','') + name FROM ta WHERE cid = @cid
RETURN @s
END
GO
SELECT DISTINCT cid,dbo.myJoinSTR(cid) nameS FROM ta
GO

/*
示例 3
列拆分为行.
以上例生成的数据格式为示例表,将a,b,c以,分融成行,即上个示例的反操作
*/

SELECT DISTINCT cid,dbo.myJoinSTR(cid) nameS INTO tx FROM ta
GO
SELECT * FROM tx
GO
--以系统表构建identity列,并以连表方式来将列拆成行
SELECT IDENTITY(INT,1,1) id INTO # FROM syscolumns,sysobjects

SELECT id,cid,RIGHT(STUFF(nameS+',',id,LEN(names),''),CHARINDEX(',',REVERSE(STUFF(','+nameS+',',id,LEN(names),'')))) name
FROM tx a
INNER JOIN # b
ON SUBSTRING(names+',',id,1)=','
ORDER BY cid
--以动态语句或循环,或函数的方式略去


/*示例 4
行转列
这是论坛上问的最多的,没啥好说的,照猫画虎。
*/

--单表,以ta为例. 静态行转列,设cid所有出现的可能值已知
SELECT
cid_1=MAX(CASE WHEN cid=1 THEN name ELSE NULL END),
cid_2=MAX(CASE WHEN cid=2 THEN name ELSE NULL END),
cid_3=MAX(CASE WHEN cid=3 THEN name ELSE NULL END)
FROM ta
--单表,以ta为例,动态行转列,设cid所有出现的可能值未知

DECLARE @s VARCHAR(8000)
SET @s=''
SELECT @s=@s + ',cid_' + RTRIM(cid) + '= MAX(CASE WHEN cid=' + RTRIM(cid) + ' THEN name ELSE null END) ' FROM ta GROUP BY cid
SELECT @s='SELECT ' + STUFF(@s,1,1,'') + ' FROM ta'
--你可以在这里PRINT @s 看看,就知道跟上面的静态行转列一样的了。 会写静态行转列,就没理由写不出动态的。多表的同理,把多表的静态行转列写出来,那么动态的也就出来了
EXEC(@s)
GO

DROP TABLE tx,#
GO

DROP TABLE ta,tb
DROP FUNCTION myJoinSTR
GO
...全文
3470 154 打赏 收藏 转发到动态 举报
写回复
用AI写文章
154 条回复
切换为时间正序
请发表友善的回复…
发表回复
sign_in 2012-08-31
  • 打赏
  • 举报
回复
好呀,支持!!!
sunhouse005 2011-03-17
  • 打赏
  • 举报
回复
GOOD 感谢楼主,我成功有你的一半。
wlv404 2010-10-12
  • 打赏
  • 举报
回复
收藏一下.时间一常就忘了.
tianzij 2009-07-22
  • 打赏
  • 举报
回复
学习了
lufy_king 2009-05-18
  • 打赏
  • 举报
回复
mark
wea1978 2009-04-13
  • 打赏
  • 举报
回复
如果列不确定,要弄一个行转列,在视图中怎么查询呢?
ggsysy 2009-01-14
  • 打赏
  • 举报
回复
收藏了。。经典。。
worlddba 2009-01-04
  • 打赏
  • 举报
回复
UP
  • 打赏
  • 举报
回复
不错,学习了。。
请输入... 2008-12-29
  • 打赏
  • 举报
回复
收藏
QSHH500 2008-10-21
  • 打赏
  • 举报
回复
ding
bing110 2008-10-21
  • 打赏
  • 举报
回复
呵呵,收藏起来了。
ybkenan 2008-08-22
  • 打赏
  • 举报
回复
我再來頂一下。
vwfkyy 2008-07-26
  • 打赏
  • 举报
回复
谢谢楼主的无私奉献。
收藏了、
littlekeen 2008-01-28
  • 打赏
  • 举报
回复
mark
zrf2006 2008-01-28
  • 打赏
  • 举报
回复
sf
zrf2006 2008-01-28
  • 打赏
  • 举报
回复
jf
zrf2006 2008-01-28
  • 打赏
  • 举报
回复
up
pzhuyy 2008-01-28
  • 打赏
  • 举报
回复
rouqu 2008-01-28
  • 打赏
  • 举报
回复
夸张哦
加载更多回复(134)

34,597

社区成员

发帖
与我相关
我的任务
社区描述
MS-SQL Server相关内容讨论专区
社区管理员
  • 基础类社区
  • 二月十六
  • 卖水果的net
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧