逗号分隔65000条记录的逻辑。 [英] Comma Seperated logic over a 65000 Records.

查看:85
本文介绍了逗号分隔65000条记录的逻辑。的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

嘿伙计们,



请帮我构建一个逻辑,根据3列和65000记录集提供逗号分隔的结果集。

我尝试过使用STUFF,COALESCE,SUBSTRING,当查询完成执行时,我可以泡一杯茶.. :(:P。



注意:

SQL Server:MSSQL 2005.

类型国家年文件名FileID 
新加坡2010 A. xls 20
A新加坡2010 B.xls 21
A新加坡2010 C.Xls 22
A马来西亚2008 A.xls 55
A马来西亚2008 B.xls 53
B Malaysia 2008 Cat.xls 88
B Malaysia 2008 doll.xls 78


预期产出
类型国家年份文件名FileID
新加坡2010 a。 xls,b.xls,c.xls 20,21,22
A Malaysia 2008 a.xls,b.xls 55,53
B Malaysia 2008 cat.xls,doll.xls 88,78

解决方案

任何ef堡垒?



无论如何,这应该有效:



 SELECT 
[type],
Country,
[Year],
fileName =
STUFF((SELECT','+ fileName
FROM Records FileNameRecords
WHERE
FileNameRecords。[type] = Records。[type]
AND FileNameRecords.Country = Records.Country
AND FileNameRecords。[Year] = Records。[Year]
FOR XML PATH ('')),1,2,''),
FileId =
STUFF((SELECT','+ FileId
FROM FROM FileNameRecords
WHERE
FileNameRecords 。[type] =记录。[type]
AND FileNameRecords.Country = Records.Country
AND FileNameRecords。[Year] = Records。[Year]
FOR XML PATH('')) ,1,2,'')
FROM
记录
GROUP BY
[类型],国家,[年]
订购
类型,年份DESC


如果您想使用CTE,请参阅:

< pre lang =sql> DECLARE @ tmp TABLE (atype VARCHAR 5 ),国家 VARCHAR 30 ),aYar INT ,afilename VARCHAR 30 ),FileID INT

INSERT INTO @ tmp (atype,Country,aYear ,afilename,FileID)
VALUES ' '' 新加坡' 2010 ' A.xls' 20 ),
' A'' Singapore' 2010 ' B.xls' 21 ),
(< span class =code-string>' A'' 新加坡' 2010 ' C.Xls' 22 ),
' A'' Malaysia',< span class =code-digit> 2008 ,' A.xls',< span class =code-digit> 55 ),
' A'' 马来西亚' 2008 ' B.xls' 53 ),
' B'' 马来西亚' 2008 ' Cat.xls' 88 ),
' B' 马来西亚' 2008 ' doll。 xls' 78

; WITH CTE AS

SELECT at at ype,Country,aYear,afilename, CONVERT VARCHAR (MAX),afilename) AS fnames,FileID, CONVERT VARCHAR (MAX),FileID ) AS fIds, 1 AS LoopNo
FROM @ tmp
UNION ALL
SELECT C.atype,C.Country,C.aYear,C .afilename,C.fnames + ' ,' + T.afilename AS fnames,C.FileID,C.fids + ' ,' + T .FileId AS fIds,LoopNo + 1 AS LoopNo
FROM CTE AS C INNER JOIN
SELECT atype,Country,aYear, CONVERT VARCHAR (MAX),afilename) AS afilename, CONVERT VARCHAR (MAX),FileID) AS FileID
FROM @ tmp
AS T ON C.aType = T.aType AND C.Country = T.Country AND C.aYear = T.aYear AND C.FileID< T.FileID
WHERE CHARINDEX( CONVERT NVARCHAR 10 ),T.FileID),C.fIds)= 0

SELECT C.atype,C.Country,C.aYear,fnames,fIds
FROM CTE AS C
ORDER BY C.atype,C.Country ,C.aYear





以上查询产生:

 A Malaysia 2008 A.xls 55 
A Malaysia 2008 B.xls 53
A Malaysia 2008 B.xls,A.xls 53,55
A Singapore 2010 B.xls,C.Xls 21,22
A Singapore 2010 A. xls,B.xls 20,21
A新加坡2010 A.xls,C.Xls 20,22
新加坡2010 A.xls,C.Xls,B.xls 20,22,21
A新加坡2010 A.xls,B.xls,C.Xls 20,21,22
A新加坡2010 A.xls 20
A新加坡2010 B.xls 21
A新加坡2010 C.Xls 22
B Mala ysia 2008 Cat.xls 88
B Malaysia 2008 doll.xls 78
B Malaysia 2008 doll.xls,Cat.xls 78,88





无法保证CTE比内置SQL函数更快。根据需要更改代码。



注意:上面的示例代码显示了CTE的工作原理。



有关CTE的更多信息,请参阅:

使用common_table_expression(Transact-SQL) [ ^ ]

CTE(公用表格表达式) [ ^ ]

CTE in SQL Server [ ^ ]


Maciejs解决方案提醒我,几年前我解决了这个问题。 链接 [ ^ ]

根据您的需求调整它看起来类似于this:

  CREATE   TABLE 记录
([类型] varchar 1 ),[Country] < span class =code-keyword> varchar ( 9 ),[年] int ,[filename] varchar 8 ),[FileID] int
;

CREATE INDEX records_ix
ON 记录
([类型],[国家],[年份],[文件名])
INCLUDE( [写到FileID]);

INSERT INTO 记录
([ type ],[Country],[Year],[filename],[FileID])
VALUES
' A'' < span class =code-string> Singapore', 2010 ' A.xls' 20 ),
' A'' Singapore' 2010 ' B.xls' 21 ),
' A '' 新加坡' 2010 ' C.Xls' 22 ),
' '' 马来西亚' 2008 ' A.xls' 55 ),
' A'' Malaysia' 2008 ' B.xls' 53 ),
' B'' 马来西亚' 2008 ' Cat.xls', 88 ),
' B'' 马来西亚' 2008 ' doll.xls' 78
;

WITH 排名 AS
SELECT [ type ],[Country],[Year],[filename],[FileID],Rank() over PARTITION BY [ type ],[Country],[Year] ORDER BY [filename] )Rnk
FROM 记录

,cte([ type ],[Country],[Year],FileNames,FileIDs,rnk) as

SELECT [ type ]
,[Country]
,[Year]
,cast([FileName] as varchar (max)) as 文件名
,强制转换([FileID] as varchar (max)) as FileID
,rnk
FROM 排名r
WHERE rnk = 1
UNION ALL
SELECT cte。[ type ]
,cte。[Country]
,cte。[Year]
,FileNames + ' < span class =code-string>,' + [FileName]
,FileIDs + ' ,' + cast([FileID] as varchar (max))
,r.rnk
FROM cte
INNER JOIN 排名r
ON cte。[ type ] = r。[ type ]
AND cte。[Country] = r。[Country]
AND cte。[Year] = r 。[年]
AND cte.Rnk = r.rnk - 1

SELECT [ type ],[Country],[Year],Max(FileNames) FileNames,Max(FileIDs)FileIDs,Max(rnk)
FROM cte
GROUP BY [ type ],[Country],[Year]
ORDER BY [ type ],[年] desc



请注意记录表上的覆盖复合索引。

仍然无法保证它更快,但适当的索引很重要。


Hey guys,

Please help me in building a logic that gives a comma seperated result set based on 3 columns and over a 65000 record set.
I've tried using STUFF, COALESCE, SUBSTRING, by the time the query completes execution, I can make a cup of tea.. :( :P.

Note:
SQL Server : MSSQL 2005.

type	Country	        Year	filename	FileID
A	Singapore	2010	A.xls	        20
A	Singapore	2010	B.xls	        21
A	Singapore	2010	C.Xls	        22
A	Malaysia	2008	A.xls	        55
A	Malaysia	2008	B.xls	        53
B	Malaysia	2008	Cat.xls	        88
B	Malaysia	2008	doll.xls	78
				
				
Expected output				
type	Country	        Year	filename	        FileID
A	Singapore	2010	a.xls,b.xls,c.xls	20,21,22
A	Malaysia	2008	a.xls,b.xls	        55,53
B	Malaysia	2008	cat.xls,doll.xls	88,78

解决方案

Any effort?

Anyway, this should work:

SELECT 
	[type], 
	Country, 
	[Year], 
	fileName = 
		STUFF((SELECT ', ' + fileName
           FROM Records FileNameRecords
           WHERE 
				FileNameRecords.[type] = Records.[type]
				AND FileNameRecords.Country = Records.Country
				AND FileNameRecords.[Year] = Records.[Year]
          FOR XML PATH('')), 1, 2, ''),
    FileId = 
		STUFF((SELECT ', ' + FileId
           FROM Records FileNameRecords
           WHERE 
				FileNameRecords.[type] = Records.[type]
				AND FileNameRecords.Country = Records.Country
				AND FileNameRecords.[Year] = Records.[Year]
          FOR XML PATH('')), 1, 2, '')
FROM	
	Records
GROUP BY
	[type], Country, [Year]
ORDER BY
	type, Year DESC


If you want to use CTE, please see:

DECLARE @tmp TABLE (atype VARCHAR(5), Country VARCHAR(30), aYear INT, afilename VARCHAR(30), FileID INT)

INSERT INTO @tmp (atype, Country, aYear, afilename, FileID)
VALUES('A', 'Singapore', 2010, 'A.xls', 20),
('A', 'Singapore', 2010, 'B.xls', 21),
('A', 'Singapore', 2010, 'C.Xls', 22),
('A', 'Malaysia', 2008, 'A.xls', 55),
('A', 'Malaysia', 2008, 'B.xls', 53),
('B', 'Malaysia', 2008, 'Cat.xls', 88),
('B', 'Malaysia', 2008, 'doll.xls', 78)

;WITH CTE AS
(
    SELECT atype, Country, aYear, afilename, CONVERT(VARCHAR(MAX),afilename) AS fnames, FileID, CONVERT(VARCHAR(MAX),FileID) AS fIds, 1 AS LoopNo
    FROM @tmp
    UNION ALL
    SELECT C.atype, C.Country, C.aYear, C.afilename, C.fnames + ',' + T.afilename AS fnames, C.FileID, C.fids + ',' + T.FileId AS fIds, LoopNo + 1 AS LoopNo
    FROM CTE AS C INNER JOIN (
        SELECT atype, Country, aYear, CONVERT(VARCHAR(MAX),afilename) AS afilename, CONVERT(VARCHAR(MAX),FileID) AS FileID
        FROM @tmp
        ) AS T ON C.aType = T.aType AND C.Country = T.Country AND C.aYear = T.aYear AND C.FileID < T.FileID
    WHERE CHARINDEX(CONVERT(NVARCHAR(10),T.FileID), C.fIds)=0
)
SELECT C.atype, C.Country, C.aYear, fnames, fIds
FROM CTE AS C
ORDER BY C.atype, C.Country, C.aYear



Above query produces:

A	Malaysia	2008	A.xls			55
A	Malaysia	2008	B.xls			53
A	Malaysia	2008	B.xls,A.xls		53,55
A	Singapore	2010	B.xls,C.Xls		21,22
A	Singapore	2010	A.xls,B.xls		20,21
A	Singapore	2010	A.xls,C.Xls		20,22
A	Singapore	2010	A.xls,C.Xls,B.xls	20,22,21
A	Singapore	2010	A.xls,B.xls,C.Xls	20,21,22
A	Singapore	2010	A.xls			20
A	Singapore	2010	B.xls			21
A	Singapore	2010	C.Xls			22
B	Malaysia	2008	Cat.xls			88
B	Malaysia	2008	doll.xls		78
B	Malaysia	2008	doll.xls,Cat.xls	78,88



There is no guarantee that CTE will be faster than in-build SQL functions. Change the code to your needs.

Note: Above sample code shows how CTE work.

For further information about CTE, please see:
WITH common_table_expression (Transact-SQL)[^]
CTEs (Common Table Expressions)[^]
CTE In SQL Server[^]


Maciejs solution reminded me that I solved that problem a couple of years ago. Link[^]
Adjusted for your needs it would look similar to this:

CREATE TABLE Records
	([type] varchar(1), [Country] varchar(9), [Year] int, [filename] varchar(8), [FileID] int)
;

CREATE INDEX records_ix
     ON Records
       ([type], [Country], [Year], [filename])
     INCLUDE ([FileID]);
	
INSERT INTO Records
	([type], [Country], [Year], [filename], [FileID])
VALUES
	('A', 'Singapore', 2010, 'A.xls', 20),
	('A', 'Singapore', 2010, 'B.xls', 21),
	('A', 'Singapore', 2010, 'C.Xls', 22),
	('A', 'Malaysia', 2008, 'A.xls', 55),
	('A', 'Malaysia', 2008, 'B.xls', 53),
	('B', 'Malaysia', 2008, 'Cat.xls', 88),
	('B', 'Malaysia', 2008, 'doll.xls', 78)
;

WITH ranked AS (
    SELECT  [type], [Country], [Year], [filename], [FileID], Rank() over (PARTITION BY [type], [Country], [Year] ORDER BY [filename]) Rnk 
    FROM    Records
    )
,cte ([type], [Country], [Year], FileNames, FileIDs, rnk) as
    (
    SELECT  [type]
           ,[Country]
           ,[Year]
           ,cast([FileName] as varchar(max)) as Filenames
           ,cast([FileID] as varchar(max)) as FileIDs
           ,rnk
    FROM    Ranked r
    WHERE   rnk = 1
    UNION ALL
    SELECT  cte.[type]
           ,cte.[Country]
           ,cte.[Year]
           ,FileNames + ', ' + [FileName]
           ,FileIDs + ', ' + cast([FileID] as varchar(max))
           ,r.rnk
    FROM    cte
    INNER JOIN ranked r
        ON  cte.[type] = r.[type]
        AND cte.[Country] = r.[Country]
        AND cte.[Year] = r.[Year]
        AND cte.Rnk = r.rnk - 1
    )
SELECT  [type], [Country], [Year], Max(FileNames) FileNames, Max(FileIDs) FileIDs, Max(rnk)
FROM    cte
GROUP BY [type], [Country], [Year]
ORDER BY [type], [Year] desc


Note the covering composite Index on the record table.
Still no guarantee that it's faster, but a proper index is important.


这篇关于逗号分隔65000条记录的逻辑。的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆