【问题标题】:complex QUERY into VIEW with WHERE clause使用 WHERE 子句将复杂的 QUERY 查询到 VIEW
【发布时间】:2021-08-15 18:07:36
【问题描述】:

我有一个如下所示的计划表:

我想要一个 SQL,它可以让我选择每个 artikelnr、日期和 jahr_kw(日历周),如果条目为空,它将采用前一个日期的条目。这是这样的:

select distinct artikelnr
            , datum
            , jahr_kw
            , first_value(menge) over (partition by artikelnr, jahr_kw 
                              order by (case when menge is not null then 1 else 2 end), datum desc
                             ) as imputed_Jahr_KW

from test_table
where datum between '2021-02-01' and '2021-03-01' -- for example

注意 where 子句。

现在我的问题是,我如何查看这个查询,我可以在 where 子句中选择日期(基准)?

【问题讨论】:

  • 您不会在视图中选择日期。也许您想要一个返回表格的用户定义函数?
  • 创建一个没有 where 子句的视图

标签: sql sql-server view


【解决方案1】:

也许表值函数是最好的

示例

CREATE FUNCTION [dbo].[tvf_SomeName](@Date1 date,@Date2 date)
Returns Table 
As
Return (  
    
select distinct artikelnr
            , datum
            , jahr_kw
            , first_value(menge) over (partition by artikelnr, jahr_kw 
                              order by (case when menge is not null then 1 else 2 end), datum desc
                             ) as imputed_Jahr_KW

from test_table
where datum between @Date1 and @Date2


);

用法

Select * From [dbo].[tvf_SomeName]('2021-02-01','2021-03-01')

【讨论】:

  • 这行得通!非常感谢!...Errr... 是否有可能让它与众不同?那太棒了:)
  • @KingsleyObeng 总是乐于提供帮助。不知道你所说的 DISTINCT 是什么意思,你已经在 TVF 中有 DISTINCT。在用法中...您可以 Select DISTINCT ColX,ColY From [dbo].[tvf_SomeName]('2021-02-01','2021-03-01')
  • @KingsleyObeng 表值函数很像一个存储过程(无更新),但有一些额外的好处。结果可以在查询中使用,即 JOIN 或 CROSS APPLY。我个人避免视图,因为它们可能会变得昂贵......尤其是大桌子。
【解决方案2】:

您可以根据需要使用索引视图。

需要如下形式的索引,查询会很快

CREATE TABLE Yourdb.test_table(artikelnr int,datum Date,jahr_kw smallint,menge INT )
GO
    CREATE VIEW Yourdb.testview
    WITH SCHEMABINDING
       AS  
          select distinct artikelnr
            , datum
            , jahr_kw
            , first_value(menge) over (partition by artikelnr, jahr_kw 
                              order by (case when menge is not null then 1 else 2 end),   datum desc
                             ) as imputed_Jahr_KW

         from test.test_table
    GO
GO
    --Create an index on the view.
    CREATE  INDEX IDX_V1   ON Yourdb.testview (datum);
    GO
GO

db小提琴here

用法

SELECT * FROM Yourdb.testview WHERE where datum between '2021-02-01' and '2021-03-01'

【讨论】:

    【解决方案3】:

    删除distinct 并简单地创建视图

    create view SomeView
    as
    select        artikelnr
                , datum
                , jahr_kw
                , first_value(menge) over (partition by artikelnr, jahr_kw 
                                  order by (case when menge is not null then 1 else 2 end), datum desc
                                 ) as imputed_Jahr_KW
    
    from test_table
    

    由于datum 是由视图投影而没有应用任何查询运算符,因此您可以从视图外部有效地对其进行过滤。

    select *
    from SomeView
    where datum between '2021-02-01' and '2021-03-01' 
    

    EG:

    drop table if exists test_table
    
    create table test_table
    (
      artikelnr int,
      datum varchar(20),
      jahr_kw int, 
      menge int
    )
    insert into test_table
    values 
     (1,'01.Jan',1,10),
     (1,'01.Jan',2,7),
     (1,'01.Jan',3,1),
     (1,'02.Jan',1,null),
     (1,'02.Jan',2,5),
     (1,'02.Jan',3,2),
     (1,'03.Jan',1,null),
     (1,'03.Jan',2,4),
     (1,'03.Jan',3,3),
     (1,'04.Jan',1,null),
     (1,'04.Jan',2,9),
     (1,'04.Jan',3,4),
     (1,'01.Jan',1,20),
     (1,'01.Jan',2,10),
     (1,'01.Jan',3,4),
     (1,'02.Jan',1,30),
     (1,'02.Jan',2,20),
     (1,'02.Jan',3,3),
     (1,'03.Jan',1,null),
     (1,'03.Jan',2,15),
     (1,'03.Jan',3,2)
     
    
     
     go
    
    create or alter view vT
    as
     select artikelnr
                , datum
                , jahr_kw
                , first_value(menge) over (partition by artikelnr, jahr_kw 
                                  order by (case when menge is not null then 1 else 2 end), datum desc
                                 ) as imputed_Jahr_KW
    
    from test_table
    
    go
    
     select distinct artikelnr
                , datum
                , jahr_kw
                , first_value(menge) over (partition by artikelnr, jahr_kw 
                                  order by (case when menge is not null then 1 else 2 end), datum desc
                                 ) as imputed_Jahr_KW
    
    from test_table
    where datum between '01.Jan' and '03.Jan' -- for example
    
    
    select *
    from vt 
    where datum between '01.Jan' and '03.Jan' -- for example
    

    【讨论】:

    • 这不能正常工作,因为它先使用整个表,然后再应用 where 子句。这可以在省略日期 1.1 时看到。从 where 子句,并在结果中从 kw1 (1.1) 即 10 中找到结果。
    • 不,那只是因为first_value 需要一些扫描。跟有没有风景没关系。通过示例查看更新的答案。
    猜你喜欢
    • 2010-12-27
    • 2021-08-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多