SQL根据驱动程序表

时间:2016-05-14 23:52:21

标签: sql-server

所有

请在下表中查看以下数据:

FIRST表:或驱动程序表包含用于从第二个表中选择ID的过滤条件

Key1    Value
1    Banks
1    Col1|Small
2    InsuranceCompany
2    Col2|Global
3    Banks
3    Col1|Big
3    Col2|Local
4    CreditUnion

脚本

GO
CREATE TABLE [dbo].[TEST_DRIVER](
    [Key1] [int] NOT NULL,
    [Value] [varchar](50) NOT NULL
    );
GO
INSERT INTO dbo.TEST_DRIVER(Key1, Value)
VALUES('1', 'Banks');
GO
INSERT INTO dbo.TEST_DRIVER(Key1, Value)
VALUES('1', 'Col1|Small');
GO
INSERT INTO dbo.TEST_DRIVER(Key1, Value)
VALUES('2', 'InsuranceCompany');
GO
INSERT INTO dbo.TEST_DRIVER(Key1, Value)
VALUES('2', 'Col2|Global');
GO
INSERT INTO dbo.TEST_DRIVER(Key1, Value)
VALUES('3', 'Banks');
GO
INSERT INTO dbo.TEST_DRIVER(Key1, Value)
VALUES('3', 'Col1|Big');
GO
INSERT INTO dbo.TEST_DRIVER(Key1, Value)
VALUES('3', 'Col2|Local');
GO
INSERT INTO dbo.TEST_DRIVER(Key1, Value)
VALUES('4', 'CreditUnion');
GO

注意: a)过滤标准可以存在1,2或3行。 b)第一个选择标准将始终与第二个表的InstitutionType列连接,但是第二个和第三个标准可能存在也可能不存在,并且它将加入的列在数据本身中指定为|用值

分隔列名称

第二表:需要根据FIRST表中的过滤条件找到此表中的ID

ID  InstitutionType     Col1        Col2
100 Banks               Small   
200 Banks                           Global
300 Banks               Big         Local
400 InsuranceCompany    Small       Local
500 InsuranceCompany                Global
600 CreditUnion         Small       Local
700 CreditUnion                     Global
800 CDO                             Global

脚本

CREATE TABLE [dbo].[TEST_TARGET](
    [ID] [int] NOT NULL,
    [InstitutionType] [varchar](50) NOT NULL,
    [Col1] [varchar](50) NULL,
    [Col2] [varchar](50) NULL
    );
GO
INSERT INTO [dbo].[TEST_TARGET](ID, InstitutionType, Col1, Col2)
VALUES('100',  'Banks', 'Small', '');
GO
INSERT INTO [dbo].[TEST_TARGET](ID, InstitutionType, Col1, Col2)
VALUES('200',  'Banks', '', 'Global');
GO
INSERT INTO [dbo].[TEST_TARGET](ID, InstitutionType, Col1, Col2)
VALUES('300',  'Banks', 'Big', 'Local');
GO
INSERT INTO [dbo].[TEST_TARGET](ID, InstitutionType, Col1, Col2)
VALUES('400',  'InsuranceCompany', 'Small', 'Local');
GO
INSERT INTO [dbo].[TEST_TARGET](ID, InstitutionType, Col1, Col2)
VALUES('500',  'InsuranceCompany', '', 'Global');
GO
INSERT INTO [dbo].[TEST_TARGET](ID, InstitutionType, Col1, Col2)
VALUES('600',  'CreditUnion', 'Small', 'Local');
GO
INSERT INTO [dbo].[TEST_TARGET](ID, InstitutionType, Col1, Col2)
VALUES('700',  'CreditUnion', '', 'Global');
GO
INSERT INTO [dbo].[TEST_TARGET](ID, InstitutionType, Col1, Col2)
VALUES('800',  'CDO', '', 'Global');
GO

预期输出:

ID
100
300
500
600
700

我可以使用cursor / while循环来完成它但是我想使用查询逻辑来完成它。有人可以试着回答这个有趣的问题吗?

2 个答案:

答案 0 :(得分:0)

你真正想要的是像这样的表

Key1 Value            Col1   Col2
1    Banks            Small
2    InsuranceCompany        Global
3    Banks            Big    Local
4    CreditUnion

如果你不能以这种方式开始,那么你可以像这样改变它:

SELECT D.Key1, D.Value, SUBSTRING(C1.Value,6) AS Col1, SUBSTRING(C2.Value,6) AS Col2
FROM DRIVER D
JOIN DRIVER c1 on D.Key1 = c1.Key1 AND LEFT(c1.Value,5) = 'Col1|'
JOIN DRIVER c2 on D.Key1 = c2.Key1 AND LEFT(c2.Value,5) = 'Col2|'
WHERE LEFT(D.Value,3) != 'Col'

现在您只需加入即可获得结果:

SELECT ID
FROM TABLE2
JOIN (
  SELECT D.Key1, D.Value, SUBSTRING(C1.Value,6) AS Col1, SUBSTRING(C2.Value,6) AS Col2
  FROM DRIVER D
  JOIN DRIVER c1 on D.Key1 = c1.Key1 AND LEFT(c1.Value,5) = 'Col1|'
  JOIN DRIVER c2 on D.Key1 = c2.Key1 AND LEFT(c2.Value,5) = 'Col2|'
  WHERE LEFT(D.Value,3) != 'Col'
) x ON TABLE2.InstitutionType = x.Key1 
     AND COALESCE(x.col1,TABLE2.Col1) = TABLE2.Col1
     AND COALESCE(x.col2,TABLE2.Col2) = TABLE2.Col2

您也可以像这样进行连接(可能或多或少都清楚,但是相同)

) x ON (x.Key1, COALESCE(x.col1,TABLE2.Col1), COALESCE(x.col2,TABLE2.Col2)) = 
       (TABLE2.InstitutionType, TABLE2.Col1, TABLE2.Col2)

我没有测试,所以我可能会在子字符串上输入一个拼写错误。

答案 1 :(得分:0)

下面的代码将起作用并产生与样本输出相同的结果,但看起来与匹配记录的方式略有不同。看起来你只匹配Value而忽略了col1&驱动程序表中的col2如果它们都不可用(这就是为什么你选择600和700),而不是如果存在一个或另一个?我希望一旦驱动程序表以正确的格式转换为col1和col2,你就可以在所有列上加入它,如下所示:

on t.InstitutionType = d.Value
and coalesce(t.col1,'') = coalesce(d.col1,'')
and coalesce(t.col2,'') = coalesce(d.col2,'')

如果您的示例输出中出现错误,您可以在下面的代码中更新连接条件。

with test_driver_cte AS 
(select 
Key1,
max(case when Value not like '%|%' then Value end) Value,
max(case when Value like '%|%' and col = 'Col1' then value2 end) Col1,
max(case when Value like '%|%' and col = 'Col2' then value2 end) Col2
from (
    select 
        key1,
        Value,
        case when value like '%|%'
             then substring(Value, 1, 4)
        end col,
        case when value like '%|%'
             then substring(Value, 6, 10)  --change 2nd parameter to length of Value-6
        end value2                   
    from test_driver
    ) td
group by key1
)

select distinct ID 
from test_target t
join test_driver_cte d
on (t.InstitutionType = d.Value and d.col1 is null and d.col2 is null)
or (t.InstitutionType = d.Value and t.col1 = d.col1)
or (t.InstitutionType = d.Value and t.col2 = d.col2)