TSQL多表连接筛选视图,尝试根据筛选结果(而不是一个)返回多个列

问题描述 投票:1回答:2

我在过滤值模式中有四个表,我无法确定如何扩展现有视图查询以包含基于过滤结果的附加列。

一个表保存默认项目记录,我在下面的示例中称这些ItemKeys。此表还包含每个项目的默认值和默认描述。在示例中,这是dbo.Defaults表。

下一个表是一个表,用于为后续过滤表对这些项的集合进行分组。在示例中称为dbo.FilterGroup。

最后两个表是过滤器,它们指向FilterGroup和Defaults以及它们自己的值和描述。这些表仅包含Items的记录,当使用FilterGroup时,它们将按顺序进行筛选:Filter2> Filter1> Default。正如您将在示例中看到的,这意味着如果Filter1具有项目记录,它将覆盖默认值,并且Filter2将覆盖Filter1(如果存在)。

The problem

当前视图仅寻求恢复过滤器数据的Value部分,并且我必须想出一种方法来恢复生成的过滤项的ValueDescription

让我向您展示我应该更清楚地表明情况的例子:

表和数据设置:

--dbo.Defaults
IF EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE='BASE TABLE' 
    AND TABLE_NAME='Defaults') drop table dbo.Defaults; 
CREATE TABLE dbo.Defaults (
    ItemKey varchar(128),
    DefaultValue varchar(128),
    DefaultDesc varchar(512),    
) ON [PRIMARY]
GO
insert into dbo.Defaults VALUES ('Fruit1','Apple','system default value')
insert into dbo.Defaults VALUES ('Fruit2','Orange','system default value')
insert into dbo.Defaults VALUES ('Fruit3','Pear',NULL)
insert into dbo.Defaults VALUES ('Fruit4','Tomato','system default value')

--dbo.Filter group
IF EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE='BASE TABLE' 
    AND TABLE_NAME='FilterGroup') drop table dbo.FilterGroup; 
CREATE TABLE dbo.FilterGroup (
    ID integer NOT NULL
        IDENTITY (1,1) CONSTRAINT [PK_ParamFilterSet] PRIMARY KEY CLUSTERED ([ID] ASC) WITH (IGNORE_DUP_KEY = OFF),
    GroupName varchar(128)
) ON [PRIMARY]
GO
insert into FilterGroup values ('Group1')

--dbo.Filter1
IF EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE='BASE TABLE' 
    AND TABLE_NAME='Filter1') drop table dbo.Filter1; 
CREATE TABLE dbo.Filter1 (
    ItemKey varchar(128), --Defaults.ItemKey
    GroupID int, --FilterGroup.ID
    FilterValue varchar(128),
    FilterDesc varchar(512),     
) ON [PRIMARY]
GO
insert into dbo.Filter1 VALUES ('Fruit2',1,'Seedless Orange',NULL)

--dbo.Filter2
IF EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE='BASE TABLE' 
    AND TABLE_NAME='Filter2') drop table dbo.Filter2; 
CREATE TABLE dbo.Filter2 (
    ItemKey varchar(128), --Defaults.ItemKey
    GroupID int, --FilterGroup.ID
    FilterValue varchar(128),
    FilterDesc varchar(512),     
) ON [PRIMARY]
GO
insert into dbo.Filter1 VALUES ('Fruit3',1,'Pyrus Pear','filter2 value')

我的查询:

SELECT fg.GroupName as [FilterGroup]
    ,d.ItemKey as [ItemKey]
    ,coalesce(f2.FilterValue, f1.FilterValue ,d.DefaultValue) as [Value]
FROM dbo.Defaults d cross join dbo.FilterGroup fg
                    left outer join dbo.Filter1 f1 on f1.ItemKey = d.ItemKey
                                                    and f1.GroupID = fg.ID
                    left outer join dbo.Filter2 f2 on f2.ItemKey = d.ItemKey  
                                                    and f1.GroupID = fg.ID

如上所述,现有查询正确过滤,将Filter2值恢复为Filter1值,Filter1值超过默认值,如果给定项目上没有过滤器,则返回默认值。

我正在努力弄清楚的是我如何根据select coalesce set中的哪个过滤器来包含f1.FilterDesc,f2.FilterDesc或d.DefaultDesc。如何执行此连接并从coalesce中出现的表中提取“value”和“desc”列?

我非常友好地感谢您提供任何帮助!

sql sql-server tsql sql-server-2014
2个回答
1
投票

一个简单的方法是:

SELECT fg.GroupName as [FilterGroup],
       d.ItemKey as [ItemKey],
       coalesce(f2.FilterValue, f1.FilterValue, d.DefaultValue) as [Value],
       (case when f2.FilterValue is not null then 'f2'
             when f1.FilterValue is not null then 'f1'
             else 'default'
        end) as which
FROM dbo.Defaults d cross join
     dbo.FilterGroup fg left outer join
     dbo.Filter1 f1
     on f1.ItemKey = d.ItemKey and f1.GroupID = fg.ID left outer join
     dbo.Filter2 f2
     on f2.ItemKey = d.ItemKey and f1.GroupID = fg.ID;

一种更聪明的方式将逻辑放入from

SELECT fg.GroupName as [FilterGroup],
       d.ItemKey as [ItemKey],
       coalesce(f2.FilterValue, f1.FilterValue, d.DefaultValue) as [Value],
       coalesce(f2.which, f1.which, 'default') as which
FROM dbo.Defaults d cross join
     dbo.FilterGroup fg left outer join
     (SELECT f1.*, 'f1' as which
      FROM dbo.Filter1 f1
     ) f1
     on f1.ItemKey = d.ItemKey and f1.GroupID = fg.ID left outer join
     (SELECT f2.*, 'f2' as which
      FROM dbo.Filter2 f2
     ) f2
     on f2.ItemKey = d.ItemKey and f1.GroupID = fg.ID;

最后一个条件应该是f1.GroupId = fg.ID还是f2.GroupID = fg.ID


0
投票

除了戈登的答案排名方法:

;with allFilters as (
  select f.ItemKey,
         f.GroupID,
         f.FilterValue,
         f.FilterDesc ,
         2 rank --<<<
  from dbo.Filter1 f

  union all

  select f.ItemKey,
         f.GroupID,
         f.FilterValue,
         f.FilterDesc ,
         1 rank --<<<
  from dbo.Filter2 f

  union all

  select f.ItemKey,
         NULL GroupID,
         f.DefaultValue,
         f.DefaultDesc ,
         3 rank --<<<
  from dbo.Defaults f
),
filtersRanked as
(
  select f.ItemKey,
         f.GroupID,
         f.FilterValue,
         f.FilterDesc ,
         -- now computing most preferred per ItemKey
         ROW_NUMBER() OVER(PARTITION BY f.ItemKey ORDER BY f.rank ASC) rn
  from allFilters f
)

SELECT fg.GroupName as [FilterGroup],
    f.ItemKey as [ItemKey],
    f.FilterValue,
    f.FilterDesc
FROM dbo.FilterGroup fg
left join filtersRanked f
  on (f.GroupID = fg.ID or f.GroupID is NULL) -- NULL support for defaults
    and f.rn = 1 --<<< "top 1" by rank

易于操纵哪个源具有更高的优先级。

输出:

FilterGroup ItemKey FilterValue FilterDesc
Group1  Fruit1  Apple           system default value
Group1  Fruit2  Seedless Orange (null)
Group1  Fruit3  Pyrus Pear      filter2 value
Group1  Fruit4  Tomato          system default value

http://sqlfiddle.com/#!18/1511d/1

你也有一些错别字:

  • 'Pyrus Pear'我想应该插入Filter2
  • f1.GroupID的连接谓词中提到Filter2而不是f2.GroupID
© www.soinside.com 2019 - 2024. All rights reserved.