在另一个字符串中查找字符串的任何部分transact sql

时间:2017-10-07 11:29:08

标签: sql-server string tsql

我的数据库中有字符串,表示一周中的天数:

1234567 (all days of the week)
1230567 (all days but Thursday, EU standard - day 1 is Monday)
0000067 (no day apart from Saturday and Sunday)

我需要编写一个检查重叠的SQL问题。 例如:

1234500 and 0000067 are NOT overlapping.
while 1234500 and 0030000 are overlapping (the 3).
and 1234500 and 0000567 IS overlapping (the 5).

每个条目都有一个ID,客户编号和此工作日表示。

我在想这样的事情:

SELECT
    *
FROM dbo.Customers c
JOIN dbo.Customers c2 ON c.CustomerNumber = c2.CustomerNumber
    AND c.Days <> c2.Days
WHERE 1 = 1
    AND ...?

要获得两个同一客户的条目,但当我来到WHERE语句时,我打了一个空白。在两个Days字段中查找子字符串(例如3)非常简单,但是当7个条目中的任何一个可以重叠并且我必须排除0(非活动日)时,我会感到困惑。

我需要一些帮助。

3 个答案:

答案 0 :(得分:1)

一种方法。每天匹配char字符串char并忽略0(通过替换非匹配值)。下面的查询将返回同一客户没有重叠天数(忽略0)的行。

SELECT
    *
FROM Customers c
JOIN Customers c2 ON c.CustomerNumber = c2.CustomerNumber
and c.days <> c2.days
where
(
REPLACE (substring (c.[days],1,1),'0','8') <> REPLACE (substring (c2.[days],1,1) ,'0','9')
AND 
REPLACE (substring (c.[days],2,1),'0','8') <> REPLACE (substring (c2.[days],2,1) ,'0','9')
AND
REPLACE (substring (c.[days],3,1),'0','8') <> REPLACE (substring (c2.[days],3,1) ,'0','9')
AND
REPLACE (substring (c.[days],4,1),'0','8') <> REPLACE (substring (c2.[days],4,1) ,'0','9')
AND 
REPLACE (substring (c.[days],5,1),'0','8') <> REPLACE (substring (c2.[days],5,1) ,'0','9')
AND
REPLACE (substring (c.[days],6,1),'0','8') <> REPLACE (substring (c2.[days],6,1) ,'0','9')
AND
REPLACE (substring (c.[days],7,1),'0','8') <> REPLACE (substring (c2.[days],7,1) ,'0','9')
)

答案 1 :(得分:1)

使用两个common table expressions,一个用于微小的计数表,另一个用Days分割cross apply()substring()每个位置使用微小的计数表以及count() over()窗口聚合函数,用Day计算每个CustomerNumber的出现次数。最终select显示每个重叠的Day

;with n as (
  select i from (values (1),(2),(3),(4),(5),(6),(7)) t(i)
)
, expand as (
  select c.CustomerNumber, c.Days, d.Day
    , cnt = count(*) over (partition by c.CustomerNumber, d.Day)
  from Customers c
    cross apply (
      select Day = substring(c.Days,n.i,1)
      from n
      ) d
  where d.Day > 0
)
select * 
from expand
where cnt > 1

rextester演示:http://rextester.com/SZUANG12356

使用测试设置:

create table Customers (customernumber int, days char(7))
insert into Customers values 
 (1,'1234500')
,(1,'0000067') -- NOT overlapping
,(2,'1234500')
,(2,'0030000') -- IS overlapping (the 3).
,(3,'1234500')
,(3,'0000567') -- IS overlapping (the 5).
;  

返回:

+----------------+---------+-----+-----+
| CustomerNumber |  Days   | Day | cnt |
+----------------+---------+-----+-----+
|              2 | 1234500 |   3 |   2 |
|              2 | 0030000 |   3 |   2 |
|              3 | 1234500 |   5 |   2 |
|              3 | 0000567 |   5 |   2 |
+----------------+---------+-----+-----+

<小时/> 参考:

答案 2 :(得分:1)

没有任何DDL(基础表结构),就无法理解您将要比较的数据存在的位置。也就是说,使用ngrams8k,您要做的事情很简单。

请注意此查询:

declare @searchstring char(7) = '1234500';
select * from dbo.ngrams8k(@searchstring,1);

<强>返回

position    token 
----------- ------
1           1     
2           2     
3           3     
4           4     
5           5     
6           0     
7           0     
考虑到这一点,这将对您有所帮助:

-- sample data
declare @days table (daystring char(7));
insert @days values ('0000067'),('0030000'),('0000567');

declare @searchstring char(7) = '1234500';

-- how to break down and compare the strings
select 
  searchstring    = @searchstring, 
  overlapstring   = OverlapCheck.daystring,
  overlapPosition = OverlapCheck.position,
    overlapValue    = OverlapCheck.token
from dbo.ngrams8k(@searchstring, 1) search
join 
(
  select * 
  from @days d
  cross apply dbo.ngrams8k(d.daystring,1)
  where token <> 0
) OverlapCheck on  search.position = OverlapCheck.position 
                  and search.token = OverlapCheck.token;

返回:

searchstring overlapstring overlapPosition      overlapValue
------------ ------------- -------------------- ---------------
1234500      0030000       3                    3
1234500      0000567       5                    5