ACT 和 CAT 是字谜
我必须在sql server
中编写一个函数,它接受2个字符串并给出一个布尔输出,指示它们是否都是字谜。
这在sql server中没有意义,但是,它仅用于学习目的
答案 0 :(得分:8)
SQL Server并不擅长此类事情,但在这里你是:
WITH Src AS
(
SELECT * FROM (VALUES
('CAT', 'ACT'),
('CAR', 'RAC'),
('BUZ', 'BUS'),
('FUZZY', 'MUZZY'),
('PACK', 'PACKS'),
('AA', 'AA'),
('ABCDEFG', 'GFEDCBA')) T(W1, W2)
), Numbered AS
(
SELECT *, ROW_NUMBER() OVER (ORDER BY (SELECT 1)) Num
FROM Src
), Splitted AS
(
SELECT Num, W1 Word1, W2 Word2, LEFT(W1, 1) L1, LEFT(W2, 1) L2, SUBSTRING(W1, 2, LEN(W1)) W1, SUBSTRING(W2, 2, LEN(W2)) W2
FROM Numbered
UNION ALL
SELECT Num, Word1, Word2, LEFT(W1, 1) L1, LEFT(W2, 1) L2, SUBSTRING(W1, 2, LEN(W1)) W1, SUBSTRING(W2, 2, LEN(W2)) W2
FROM Splitted
WHERE LEN(W1)>0 AND LEN(W2)>0
), SplitOrdered AS
(
SELECT *,
ROW_NUMBER() OVER (PARTITION BY Num ORDER BY L1) LNum1,
ROW_NUMBER() OVER (PARTITION BY Num ORDER BY L2) LNum2
FROM Splitted
)
SELECT S1.Num, S1.Word1, S1.Word2, CASE WHEN COUNT(*)=LEN(S1.Word1) AND COUNT(*)=LEN(S1.Word2) THEN 1 ELSE 0 END Test
FROM SplitOrdered S1
JOIN SplitOrdered S2 ON S1.L1=S2.L2 AND S1.Num=S2.Num AND S1.LNum1=S2.LNum2
GROUP BY S1.Num, S1.Word1, S1.Word2
结果:
1 CAT ACT 1
2 CAR RAC 1
3 BUZ BUS 0
4 FUZZY MUZZY 0
5 PACK PACKS 0
6 AA AA 1
7 ABCDEFG GFEDCBA 1
答案 1 :(得分:4)
首先将两个单词拆分(T-SQL Split Word into characters)到临时表中。然后执行外连接并检查空值。
感谢George的评论:
答案 2 :(得分:2)
第一个想到我的想法:
DECLARE @word1 nvarchar(max) = NULL,
@word2 nvarchar(max) = 'Test 1',
@i int = 0, @n int
DECLARE @table TABLE (
id int,
letter int
)
SELECT @word1 = ISNULL(LOWER(@word1),''), @word2 = ISNULL(LOWER(@word2),'')
SELECT @n = CASE WHEN LEN(@word1) > LEN(@word2) THEN LEN(@word1) ELSE LEN(@word2) END
WHILE @n > 0
BEGIN
INSERT INTO @table
SELECT 1, ASCII(SUBSTRING(@word1,@n,1))
UNION ALL
SELECT 2, ASCII(SUBSTRING(@word2,@n,1))
SET @n=@n-1
END
SELECT CASE WHEN COUNT(*) = 0 THEN 1 ELSE 0 END isAnagram
FROM (
SELECT id, letter, COUNT(letter) as c
FROM @table
WHERE id = 1
GROUP BY id, letter)as t
FULL OUTER JOIN (
SELECT id, letter, COUNT(letter) as c
FROM @table
WHERE id = 2
GROUP BY id, letter) as p
ON t.letter = p.letter and t.c =p.c
WHERE t.letter is NULL OR p.letter is null
输出:
isAnagram
0
答案 3 :(得分:2)
您还可以在函数中使用循环,它们可以快速工作。即使接近此功能的性能,我也无法获得任何其他答案:
CREATE FUNCTION IsAnagram
(
@value1 VARCHAR(255)
, @value2 VARCHAR(255)
)
RETURNS BIT
BEGIN
IF(LEN(@value1) != LEN(@value2))
RETURN 0;
DECLARE @firstChar VARCHAR(3);
WHILE (LEN(@value1) > 0)
BEGIN
SET @firstChar = CONCAT('%', LEFT(@value1, 1), '%');
IF(PATINDEX(@firstChar, @value2) > 0)
SET @value2 = STUFF(@value2, PATINDEX(@firstChar, @value2), 1, '');
ELSE
RETURN 0;
SET @value1 = STUFF(@value1, 1, 1, '');
END
RETURN (SELECT IIF(@value2 = '', 1, 0));
END
GO
SELECT dbo.IsAnagram('asd', 'asd')
--1
SELECT dbo.IsAnagram('asd', 'dsa')
--1
SELECT dbo.IsAnagram('assd', 'dsa')
--0
SELECT dbo.IsAnagram('asd', 'dssa')
--0
SELECT dbo.IsAnagram('asd', 'asd')
答案 4 :(得分:2)
这是数字表可以帮助的东西。
创建并填充小数字表的代码如下。
CREATE TABLE dbo.Numbers
(
Number INT PRIMARY KEY
);
WITH Ten(N) AS
(
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
)
INSERT INTO dbo.Numbers
SELECT ROW_NUMBER() OVER (ORDER BY @@SPID) AS Number
FROM Ten T10,
Ten T100,
Ten T1000
一旦到位,您可以使用
SELECT W1,
W2,
IsAnagram = CASE
WHEN LEN(W1) <> LEN(W2)
THEN 0
ELSE
CASE
WHEN EXISTS (SELECT SUBSTRING(W1, Number, 1),
COUNT(*)
FROM dbo.Numbers
WHERE Number <= LEN(W1)
GROUP BY SUBSTRING(W1, Number, 1)
EXCEPT
SELECT SUBSTRING(W2, Number, 1),
COUNT(*)
FROM dbo.Numbers
WHERE Number <= LEN(W2)
GROUP BY SUBSTRING(W2, Number, 1))
THEN 0
ELSE 1
END
END
FROM (VALUES
('CAT', 'ACT'),
('CAR', 'RAC'),
('BUZ', 'BUS'),
('FUZZY', 'MUZZY'),
('PACK', 'PACKS'),
('AA', 'AA'),
('ABCDEFG', 'GFEDCBA')) T(W1, W2)
或者替代实施可能是
IsAnagram = CASE
WHEN LEN(W1) <> LEN(W2)
THEN 0
ELSE
CASE
WHEN EXISTS (SELECT 1
FROM dbo.Numbers N
CROSS APPLY (VALUES(1,W1),
(2,W2)) V(Col, String)
WHERE N.Number <= LEN(W1)
GROUP BY SUBSTRING(String, Number, 1)
HAVING COUNT(CASE WHEN Col = 1 THEN 1 END) <>
COUNT(CASE WHEN Col = 2 THEN 1 END))
THEN 0
ELSE 1
END
END