2017-10-07 61 views
2

我在我的数据库,它表示在这样的工作日字符串:查找字符串的任何部分在另一个字符串处理SQL

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(不活跃的一天)时,我会感到困惑。

我需要一些帮助。

+0

也可能有多个重叠,我只需要确定它是否重叠,我其实不需要知道多少天或哪几天。 –

+0

*叹息*按下输入太快:1234560和0234567理论上可能存在于数据库中。 –

+0

跳跃想法的不好主意:(1)将所有非零字符更改为1,将二进制数字字符串转换为整数,然后['&'](https://docs.microsoft.com/en -us/sql/t-sql/language-elements/bitwise-and-transact-sql)(按位与)整数来检测重叠。 (2)将字符串从数字推到XML和...。 (如果持续计算的列与星期的位图的整数值一起保存,那么二进制方法可能不会那么糟糕。) – HABO

回答

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') 
) 
+0

我想到了这一点,但是当我看到完成的解决方案时,我想我自己:“这是丑陋的,是更好的方式“... –

+0

@Glaurung先生同意,应该有一些更干净的方式来做到这一点。可能是,我明天会试一试。这是一个漫长的一天。 –

+0

非常感谢您的帮助! –

1

使用两个common table expressions,一个用于一个微小的帐簿表,其他与cross apply()substring()用于使用所述小帐簿表与count() over()窗口聚合函数沿每个位置分裂Days通过计数每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 | 
+----------------+---------+-----+-----+ 


参见ENCE:

+0

非常感谢您的帮助! –

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 
+0

非常感谢您的帮助! –

相关问题