我有两列:一列包含实际答案,另一列是answer_key。
我想比较answer_key的答案并在第三栏中得分:
ID Answers Answer_key Score
1 ABCD ABCC 1110
2 ACD DCA 010
当然,我可以检查长度,循环浏览每个角色以单独比较它们,并获得分数。
然而,还有其他选择吗?可能基于XML路径?
答案 0 :(得分:0)
您可以尝试二进制值而不是字母。
A=0001 B=0010 C=0100 D=1000
ABCD = 0001001001001000 (0x1248)
ABCC = 0001001001000100 (0x1244)
Score = (Answers XOR Answer_key) XOR 11111111
XOR 11111111是可选的
答案 1 :(得分:0)
您要做的是将Answers
和Answers_Key
中的每个字符拆分为不同的行,然后进行比较。这可以使用Recursive CTE
来完成。使用FOR XML PATH
函数完成连接。
CREATE TABLE temp(
Answers VARCHAR(10),
Answer_Key VARCHAR(10)
)
INSERT INTO temp VALUES ('ABCD', 'ABCC'), ('ACD', 'DCA');
;WITH temp_numbered AS(
SELECT
ID = ROW_NUMBER() OVER(ORDER BY Answer_Key),
*
FROM temp
),
cte AS(
SELECT
ID,
Answer_Key_Char = SUBSTRING(Answer_Key, 1, 1),
Answer_Key = STUFF(Answer_Key, 1, 1, ''),
Answers_Char = SUBSTRING(Answers, 1, 1),
Answers = STUFF(Answers, 1, 1, ''),
RowID = 1
FROM temp_numbered t
UNION ALL
SELECT
ID,
Answer_Key_Char = SUBSTRING(Answer_Key, 1, 1),
Answers = STUFF(Answer_Key, 1, 1, ''),
Answers_Char = SUBSTRING(Answers, 1, 1),
Answers = STUFF(Answers, 1, 1, ''),
RowID = RowID + 1
FROM cte
WHERE LEN(Answer_Key) > 0
)
SELECT
Answers,
Answer_Key,
Score = (SELECT
CASE WHEN Answer_Key_Char = Answers_Char THEN '1' ELSE '0' END
FROM cte
WHERE ID = t.ID
ORDER BY ID, RowID
FOR XML PATH(''))
FROM temp_numbered t
DROP TABLE temp
以下是使用Tally Table
的另一种方式:
;WITH tally(N) AS(
SELECT TOP 11000 ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) FROM sys.columns
)
,temp_numbered AS(
SELECT
ID = ROW_NUMBER() OVER(ORDER BY Answer_Key),
*
FROM temp
)
,cte AS(
SELECT
ID,
Answer_Key_Char = SUBSTRING(Answer_Key, N, 1),
Answers_Char = SUBSTRING(Answers, N, 1),
RowID = N
FROM temp_numbered tn
CROSS JOIN Tally t
WHERE t.N <= LEN(tn.Answer_Key)
)
SELECT
Answers,
Answer_Key,
Score = (SELECT
CASE WHEN Answer_Key_Char = Answers_Char THEN '1' ELSE '0' END
FROM cte
WHERE ID = t.ID
ORDER BY ID, RowID
FOR XML PATH(''))
FROM temp_numbered t
答案 2 :(得分:0)
我似乎最容易在整个集合中循环遍历每个字符:
-- get max Answer length
declare @len int,@max_len int
select @max_len = max(len(Answers)),
@len = 1
from Answers
-- update scores
while @len <= @max_len
begin
update Answers
set Score = isnull(Score,'') + '1'
where substring(Answers,@len,1) = substring(Answer_Key,@len,1)
and len(Answers) >= @len
update Answers
set Score = isnull(Score,'') + '0'
where substring(Answers,@len,1) != substring(Answer_Key,@len,1)
and len(Answers) >= @len
set @len = @len + 1
end
-- return Scores
select * from Answers
<强> SQL FIDDLE 强>
答案 3 :(得分:0)
扩大@weswesthemenace的答案以克服cte限制。
DECLARE @Answers TABLE
(
Id INT IDENTITY(1, 1) not null,
Answers VARCHAR(MAX) not null,
Answer_Key VARCHAR(MAX) not null
)
INSERT INTO @Answers (Answers, Answer_Key) VALUES ('ABCD', 'ABCC')
INSERT INTO @Answers (Answers, Answer_Key) VALUES ('ACD', 'DCA')
INSERT INTO @Answers (Answers, Answer_Key) VALUES ('ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ', 'ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEGGHIJKLMNOPQRSTUVXXYZABCDEFGHIIKKMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXZZ');
WITH
E01(N) AS (SELECT 1 UNION ALL SELECT 1),
E02(N) AS (SELECT 1 FROM E01 a CROSS JOIN E01 b),
E04(N) AS (SELECT 1 FROM E02 a CROSS JOIN E02 b),
E08(N) AS (SELECT 1 FROM E04 a CROSS JOIN E04 b),
E16(N) AS (SELECT 1 FROM E08 a CROSS JOIN E08 b),
E32(N) AS (SELECT 1 FROM E16 a CROSS JOIN E16 b),
cteTally(N) AS (SELECT row_number() OVER (ORDER BY N) FROM E32)
SELECT b.Answers, b.Answer_Key,
(
SELECT CASE when SUBSTRING(a.Answer_Key, n.N, 1) = SUBSTRING(a.Answers, n.N, 1) then '1' else '0' end
FROM @Answers a
CROSS APPLY cteTally n
WHERE b.Id = a.Id AND n.N <= DATALENGTH(b.Answers)
ORDER BY ID, n.N
FOR XML PATH('')
) Score
FROM @Answers b
这可以通过数据库中的实用程序编号函数来简化。我叫做dbo.Number(开始,结束)
SELECT b.Answers, b.Answer_Key,
(
SELECT CASE WHEN SUBSTRING(a.Answer_Key, n.N, 1) = SUBSTRING(a.Answers, n.N, 1) THEN '1' ELSE '0' END
FROM @Answers a
CROSS APPLY dbo.Number(1, DATALENGTH(b.Answers)) n
WHERE b.Id = a.Id
ORDER BY ID, n.N
FOR XML PATH('')
) Score
FROM @Answers b