【发布时间】:2017-09-26 18:36:16
【问题描述】:
我有一个包含三列的表格,每列包含逗号分隔的数据,例如
AAA,BBB,CCC,DDD,...。
我想返回一个CROSS JOIN,其中包含所有列中所有标记的所有可能组合,以及每行中的一些其他列。
我有一个 Split 函数,它返回表中的标记。我传入每一列并返回一堆行。
我能想到的最好方法是使用游标,一次取每一行。完成 CROSS JOIN 后,我将所有计算的行写入工作/临时表。处理完所有行后,我从工作/临时表中选择以返回计算的行。
我的问题:有没有办法在没有工作/临时表的情况下做到这一点?
我现在的代码是:
DECLARE cPKG CURSOR FAST_FORWARD FOR SELECT ID, SEARCH, COUNTY, COMPANY FROM DEV..EXPPKG WITH(NOLOCK)
OPEN cPKG
FETCH NEXT FROM cPKG INTO @ID, @SEARCH, @COUNTY, @COMPANY
WHILE @@FETCH_STATUS = 0
BEGIN
INSERT INTO DEV..PKG_DUMP_WORK
(ID,
PKG_CODE,
PRICE,
CNTY,
CPNY,
SRCH,
SEARCH,
COUNTY,
COMPANY,
SRCH_COUNT,
UPDT_DT,
UPDT_BY,
UPDT_CMT)
SELECT PKG.ID,
PKG.PKG_CODE,
PKG.PRICE,
CNTY.VALUE AS CNTY,
CPNY.VALUE AS CPNY,
SRCH.VALUE AS SRCH,
PKG.SEARCH,
PKG.COUNTY,
PKG.COMPANY,
PKG.SRCH_COUNT,
PKG.UPDT_DT,
PKG.UPDT_BY,
PKG.UPDT_CMT
FROM (SELECT *
FROM DEV..EXPPKG WITH(NOLOCK)
WHERE ID = @ID) PKG
CROSS JOIN DBO.Split(@SEARCH, ',') SRCH -- AAA,BBB,CCC...
CROSS JOIN DBO.Split(@COUNTY, ',') CNTY -- DDD,EEE,FFF..
CROSS JOIN DBO.Split(@COMPANY, ',') CPNY -- GGG,HHH,KKK...
FETCH NEXT FROM cPKG INTO @ID, @SEARCH, @COUNTY, @COMPANY
END
CLOSE cPKG
DEALLOCATE cPKG
一些数据:
INSERT INTO [EXPPKG] ( PKG_CODE, PRICE, SEARCH, COUNTY, COMPANY, SRCH_COUNT, UPDT_DT, UPDT_BY, UPDT_CMT ) VALUES ( 'A-2', 999, 'CO,ER,FC,HB,ST,TX', 'BX,KG,QN,RI', ',AAN,ALR,CITI,GRANITE,HARB,LLS,LTTA,MADI,NARROW,REGENCY,', 6, NULL, NULL, NULL );
INSERT INTO [EXPPKG] ( PKG_CODE, PRICE, SEARCH, COUNTY, COMPANY, SRCH_COUNT, UPDT_DT, UPDT_BY, UPDT_CMT ) VALUES ( 'AM-2', 999, 'CO,ER,FC,HB,ST,TX', 'MA', ',ALR,CITI,GRANITE,INTER,LTTA,MADI,SKYLINE,', 6, NULL, NULL, NULL );
INSERT INTO [EXPPKG] ( PKG_CODE, PRICE, SEARCH, COUNTY, COMPANY, SRCH_COUNT, UPDT_DT, UPDT_BY, UPDT_CMT ) VALUES ( 'B-2', 999, 'AR,CO,ER,FC,HB,HI,HL,ST,TX', 'BX,KG,QN,RI', ',C&C,LTTA,', 9, NULL, NULL, NULL );
INSERT INTO [EXPPKG] ( PKG_CODE, PRICE, SEARCH, COUNTY, COMPANY, SRCH_COUNT, UPDT_DT, UPDT_BY, UPDT_CMT ) VALUES ( 'CA-2', 999, 'CO,ER,FC,HB,HI,ST,TX', 'BX,KG,MA,QN,RI', ',CANY,CHATHAM,TRAK,', 7, NULL, NULL, NULL );
INSERT INTO [EXPPKG] ( PKG_CODE, PRICE, SEARCH, COUNTY, COMPANY, SRCH_COUNT, UPDT_DT, UPDT_BY, UPDT_CMT ) VALUES ( 'CT-4', 999, 'CO,ER,FC,HB', 'BX,KG,MA,QN,RI', ',CLTLTNY,CTALB,CTIM,CTIM-711,CTIM-CC,CTIM-Q,CTIM-R,CTIMR-O,FNT,FNT-A,FNT-AG,FNT-N,FNT-R,NYLS,TICOR,TICORROC,FNT-RAM,', 4, NULL, NULL, NULL );
【问题讨论】:
-
你为什么要使用光标?这里根本不需要游标。这应该是一个插入语句。您的拆分功能有什么?更多循环?分隔数据是糟糕的设计,因为它违反了 1NF。而那些 NOLOCK 的暗示也比大多数人意识到的要险恶得多。
-
SL:数据不是我设计的,无法更改。这些列包含逗号分隔的数据,如 AAA、BBB、CCC.. 每行包含三个这样的列。列可能包含 1-N 个标记 - 无法预测。 SPLIT 获取一列并将其转换为每个分隔标记的一行,以便它们可以被交叉。如果你有办法一次性做到这一点,我想听听。
-
我相信 CROSS APPLY 是答案,但数据库兼容性是古老的。切换到一个新的数据库,它的工作原理。
标签: sql-server tsql cursor temp-tables