#sql #sql-server
Вопрос:
Моя база данных-SQL Server. У меня есть поле с номером телефона. Я должен вернуть НЕДОПУСТИМОЕ значение, если номер телефона содержит одну и ту же цифру, повторяющуюся более 7 раз? Например (401) 2510897 —> Допустимо. (401) 4444444 —-> Недействительный.
Комментарии:
1. Не уверен, но я думаю, что вам понадобятся
1
регулярные выражения здесь, и я думаю, что это не поддерживается в MSSQL :/2. Дал ли один из приведенных ниже ответов решение? Если да, пожалуйста, подумайте о том, чтобы принять его.
Ответ №1:
ВРОДЕ бы справляется со своей работой…
SELECT
Telephone,
CASE
WHEN Telephone LIKE '%0%0%0%0%0%0%0%' THEN 'Invalid'
WHEN Telephone LIKE '%1%1%1%1%1%1%1%' THEN 'Invalid'
WHEN Telephone LIKE '%2%2%2%2%2%2%2%' THEN 'Invalid'
WHEN Telephone LIKE '%3%3%3%3%3%3%3%' THEN 'Invalid'
WHEN Telephone LIKE '%4%4%4%4%4%4%4%' THEN 'Invalid'
WHEN Telephone LIKE '%5%5%5%5%5%5%5%' THEN 'Invalid'
WHEN Telephone LIKE '%6%6%6%6%6%6%6%' THEN 'Invalid'
WHEN Telephone LIKE '%7%7%7%7%7%7%7%' THEN 'Invalid'
WHEN Telephone LIKE '%8%8%8%8%8%8%8%' THEN 'Invalid'
WHEN Telephone LIKE '%9%9%9%9%9%9%9%' THEN 'Invalid'
ELSE 'Valid'
END
FROM
MyTable
или используйте REPLICATE, чтобы было понятнее, что должно быть менее 7 совпадений…
SELECT
Telephone,
CASE
WHEN Telephone LIKE '%' REPLICATE('0%', 7) THEN 'Invalid'
WHEN Telephone LIKE '%' REPLICATE('1%', 7) THEN 'Invalid'
WHEN Telephone LIKE '%' REPLICATE('2%', 7) THEN 'Invalid'
WHEN Telephone LIKE '%' REPLICATE('3%', 7) THEN 'Invalid'
WHEN Telephone LIKE '%' REPLICATE('4%', 7) THEN 'Invalid'
WHEN Telephone LIKE '%' REPLICATE('5%', 7) THEN 'Invalid'
WHEN Telephone LIKE '%' REPLICATE('6%', 7) THEN 'Invalid'
WHEN Telephone LIKE '%' REPLICATE('7%', 7) THEN 'Invalid'
WHEN Telephone LIKE '%' REPLICATE('8%', 7) THEN 'Invalid'
WHEN Telephone LIKE '%' REPLICATE('9%', 7) THEN 'Invalid'
ELSE 'Valid'
END
FROM
MyTable
Комментарии:
1. Единственная проблема в том, что на самом деле означает «более 7»
8
. Я также должен отметить, что это легко адаптируется, если «более 7» действительно означает более 7 раз подряд.
Ответ №2:
Настоятельно рекомендуется включить это требование в программу для работы с clr или использовать его. Если вам необходимо использовать t-sql, вы можете сделать это следующим образом:
-- Auxiliary function, this function is very commonly used and can be left in the database
CREATE FUNCTION [dbo].[SplitByTrunk](@str varchar(max), @len int = 1)
RETURNS TABLE
AS
RETURN
(
with c0 as(
select @str as s
), c1 as(
select number 1 as n from master.dbo.spt_values where type = 'P' and number >= 0 and number%@len = 0
)
select ROW_NUMBER() over(order by c1.n) as pos
, SUBSTRING(c0.s, c1.n, @len) as item
from c0
inner join c1 on c1.n <= LEN(c0.s)
)
-- Then
create table #temp(num varchar(32))
insert into #temp(num) values('(401) 2510897'), ('(401) 4444444')
select num
, (case when (select MAX(cnt)
from(select COUNT(*) as cnt from [dbo].[SplitByTrunk](num, 1) group by item) as d) < 7
then 'Valid.'
else 'Invalid.'
end) as isvalid
from #temp
Значения master.dbo.spt_ в функции SplitByTrunk, если числовая последовательность недостаточно длинная, вместо этого вы можете использовать следующую функцию (эта функция также очень часто используется и может быть сохранена в базе данных)
CREATE FUNCTION [dbo].[GetNums](@low AS BIGINT, @high AS BIGINT) RETURNS TABLE
AS
RETURN
WITH
L0 AS (SELECT c FROM (VALUES(1),(1)) AS D(c)),
L1 AS (SELECT 1 AS c FROM L0 AS A CROSS JOIN L0 AS B),
L2 AS (SELECT 1 AS c FROM L1 AS A CROSS JOIN L1 AS B),
L3 AS (SELECT 1 AS c FROM L2 AS A CROSS JOIN L2 AS B),
L4 AS (SELECT 1 AS c FROM L3 AS A CROSS JOIN L3 AS B),
L5 AS (SELECT 1 AS c FROM L4 AS A CROSS JOIN L4 AS B),
Nums AS (SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS rownum
FROM L5)
SELECT @low rownum - 1 AS n
FROM Nums
ORDER BY rownum
OFFSET 0 ROWS FETCH FIRST @high - @low 1 ROWS ONLY;
Ответ №3:
Вы можете решить эту проблему с помощью некоторых оконных функций и рекурсивного cte, но — в зависимости от количества записей — производительность, я думаю, будет не такой хорошей:
DECLARE @t TABLE(
TelID int,
TelNo VARCHAR(50)
)
INSERT INTO @t VALUES
(1, '(401) 4444444')
,(2, '(401) 4444344')
;WITH cteTelPos AS(
SELECT TelID, TelNo, 1 id, LEFT(TelNo, 1) AS TelPos, RIGHT(TelNo, LEN(TelNo)-1) AS tel
FROM @t
UNION ALL
SELECT TelID, TelNo, id 1, LEFT(tel, 1), RIGHT(tel, LEN(tel)-1)
FROM cteTelPos
WHERE LEN(tel) >= 1
),
cteFilterGrp AS(
SELECT TelID, TelNo, id, TelPos
,(id - DENSE_RANK() OVER (PARTITION BY TelPos ORDER BY id)) * RANK() OVER (ORDER BY TelPos) AS grp
FROM cteTelPos
),
cteInval AS(
SELECT TelID, TelNo, TelPos, Grp, COUNT(*) cnt
FROM cteFilterGrp
GROUP BY TelID, TelNo, TelPos, Grp
HAVING COUNT(*) >= 7
),
cteInvalSrt AS(
SELECT TelID, TelNo, TelPos, Grp, cnt, ROW_NUMBER() OVER (ORDER BY cnt DESC) AS rn
FROM cteInval
)
SELECT t.*, CASE WHEN s.cnt IS NULL THEN N'Valid' ELSE N'Invalid' END AS TelStatus
FROM @t AS t
LEFT JOIN cteInvalSrt s ON s.TelID = t.TelID AND s.rn = 1