使用联合合并多个计算

Combine multiple calcs using union

提问人:Blowers 提问时间:11/15/2023 更新时间:11/16/2023 访问量:77

问:

我有多个使用联合的计算,我正在尝试将它们组合在一起,以便我可以将它们加载到同一行的新表中。

下面是一个计算示例,我总共有 8 个。我想通过存储的过程将结果加载到新的汇总表中,但我不确定如何进行合并/加载这些计算。

汇总表将包含 8 个计算列、名称列和加载日期。它只会包含 1 行,因为数据会在一天中被删除和重新加载。

--current day

select Name, count(cast (id as int))  as current_day from (
    select Name,id from [Table1]
    where CONVERT(DATE, dte_Uploaded) = CONVERT(DATE, CURRENT_TIMESTAMP)
    union all
    select Name,id from from [Table2]
    where CONVERT(DATE, dte_Uploaded) = CONVERT(DATE, CURRENT_TIMESTAMP)

) x group by Name



--current week


select Name, count(cast (id as int))  as current week from (
    select Name,id from [Table1]
    where DATEDIFF(ww, dte_Uploaded, GETDATE()) = 0
    union all
    select Name,id from from [Table2]
    where DATEDIFF(ww, dte_Uploaded, GETDATE()) = 0


) x group by  Name


--current month


select Name, count(cast (id as int))   as current_month from (
    select Name,id from [Table1]
    where DATEDIFF(m, dte_Uploaded, GETDATE()) = 0
    union all
    select Name,id from from [Table2]
    where DATEDIFF(m, dte_Uploaded, GETDATE()) = 0


) x group by  Name
sql-server 存储过程 联合

评论

0赞 jarlh 11/15/2023
from from语法错误。
0赞 jarlh 11/15/2023
current week语法错误。

答:

1赞 Littlefoot 11/15/2023 #1

如果目标表只包含一行,我假设您发布的每个查询也只包含一行。因为,如果他们不这样做,你怎么知道该选择哪一行?

无论如何:一种选择是将当前查询用作 CTE(公共表表达式;一种使用子查询的新方法),交叉连接它们并获取您感兴趣的列。

例如:

with 
current_day as(
select Name, count(cast (id as int))  as current_day from (
    select Name,id from [Table1]
    where CONVERT(DATE, dte_Uploaded) = CONVERT(DATE, CURRENT_TIMESTAMP)
    union all
    select Name,id from from [Table2]
    where CONVERT(DATE, dte_Uploaded) = CONVERT(DATE, CURRENT_TIMESTAMP)
) x group by Name),
current_week as(

select Name, count(cast (id as int))  as current_week from (
    select Name,id from [Table1]
    where DATEDIFF(ww, dte_Uploaded, GETDATE()) = 0
    union all
    select Name,id from from [Table2]
    where DATEDIFF(ww, dte_Uploaded, GETDATE()) = 0
) x group by  Name),
current month as
(
select Name, count(cast (id as int))   as current_month from (
    select Name,id from [Table1]
    where DATEDIFF(m, dte_Uploaded, GETDATE()) = 0
    union all
    select Name,id from from [Table2]
    where DATEDIFF(m, dte_Uploaded, GETDATE()) = 0
) x group by  Name)
select a.name, a.current_day, b.current_week, c.current_month
from current_day a cross join current_week b cross join current_month c;

如果交叉联接不起作用,那么您应该知道如何正确联接每个 CTE 返回的结果。


最后,如何在目标表中插入值?喜欢这个:

insert into target (name, current_day, current_week, current_month)
with current_day as (the whole query posted above goes here)
select a.name, a.current_day, b.current_week, c.current_month
from current_day a cross join current_week b cross join current_month c

评论

0赞 Blowers 11/15/2023
感谢您的回复,我在第 19 行收到不正确的语法错误,当前月份行的 CTE 错误。想知道我是否错过了什么?
0赞 Blowers 11/15/2023
我得到了 cte 返回数据,但交叉连接不起作用,因为并非所有名称值都返回,并且它为我提供了当前日期和当前周计数的多行
0赞 Littlefoot 11/16/2023
右;这就是我所说的:我假设每个查询只返回一行,因为目标表——正如你所说——总是只包含一行。如果每个查询都有多行,如何知道要采用哪一行?显然,有几个名字和它们的计数。那么,理想的结果是什么呢?如何确保目标表仅包含一行?
0赞 Blowers 11/17/2023
谢谢 Littlefoot,这不适合我的数据,但这段代码绝对对我未来的 SQL 有很大帮助,感谢您的帮助!
0赞 Littlefoot 11/18/2023
别客气。
1赞 T N 11/16/2023 #2

如果提前计算适当的日期范围并使用条件聚合来计算计数,则可能会获得更好的性能和更高的可读性。

在计算日期范围时,通常会计算一个包含的开始日期和一个独占的结束日期(第二天开始的 00:00:00)。这可以很好地处理日期/时间字段,而无需截断可能索引的列值。

条件聚合将聚合函数(在本例中)与包含或排除聚合中每个值的表达式组合在一起。因为行是计算的,而隐式的行不是。COUNT()CASECOUNT()THEN 1ELSE NULL

尝试如下操作:

-- Day, week, and month ranges. (End dates are exclusive.)
DECLARE @today      DATE = CONVERT(DATE, GETDATE())
DECLARE @day_from   DATE = @today
DECLARE @day_to     DATE = DATEADD(day, 1, @day_from)
DECLARE @week_from  DATE = DATETRUNC(week, @today)
DECLARE @week_to    DATE = DATEADD(week, 1, @week_from)
DECLARE @month_from DATE = DATETRUNC(month, @today)
DECLARE @month_to   DATE = DATEADD(month, 1, @month_from)

-- Overall range (to limit initial data retrieval)
DECLARE @range_from DATE = LEAST(@week_from, @month_from)
DECLARE @range_to   DATE = GREATEST(@week_to, @month_to)

SELECT
    Name,
    COUNT(CASE WHEN dt >= @day_from   AND dt < @day_to   THEN 1 END) AS current_day,
    COUNT(CASE WHEN dt >= @week_from  AND dt < @week_to  THEN 1 END) AS current_week,
    COUNT(CASE WHEN dt >= @month_from AND dt < @month_to THEN 1 END) AS current_month
FROM (
    SELECT Name, dte_Uploaded AS dt
    FROM Table1
    WHERE dte_Uploaded >= @range_from AND dte_Uploaded < @range_to
    UNION ALL
    SELECT Name, dte_Uploaded AS dt
    FROM Table2
    WHERE dte_Uploaded >= @range_from AND dte_Uploaded < @range_to
) X
GROUP BY Name

如果对dte_Uploaded编制了索引,则上述操作将仅有效地检索当前计算所需的那些行,而不是效率较低的表扫描。

如果使用的是不支持 、 和 函数的旧版本的 SQL Server,则可以使用以下备用日期计算:DATETRUNC()LEAST()GREATEST()

-- Day, week, and month ranges. (End dates are exclusive.)
DECLARE @today      DATE = CONVERT(DATE, GETDATE())
DECLARE @day_from   DATE = @today
DECLARE @day_to     DATE = DATEADD(day, 1, @today)
DECLARE @week_from  DATE = DATEADD(day, 1 - DATEPART(weekday, @today), @today)
DECLARE @week_to    DATE = DATEADD(week, 1, @week_from)
DECLARE @month_from DATE = DATEADD(day, 1 - DAY(@today), @today)
DECLARE @month_to   DATE = DATEADD(month, 1, @month_from)

-- Overall range (to limit initial data retrieval)
DECLARE @range_from DATE = CASE WHEN @week_from < @month_from THEN @week_from ELSE @month_from END
DECLARE @range_to   DATE = CASE WHEN @week_to > @month_to THEN @week_to ELSE @month_to END

根据您的网站定义一周开始时间的方式,可能需要调整一周范围。

评论

0赞 Blowers 11/16/2023
谢谢T N!这看起来是有效的,需要额外的几个计算;当前年份、前一天、前一周、上个月、前一年。在声明语句下,这些需要哪些日期变量?
0赞 T N 11/16/2023
好吧,可以使用与计算当前周或月开始时间相同的技术来计算当前@year_ - 或者(对于较旧的SQL Server版本)。以前的开始日期可以与其他日期进行计算。以前的 to-date 将等于相应的当前 from-date。DATETRUNC(...)DATEADD(day, 1 - DATEPART(dayofyear, @today), @today)DATEADD(..., -1, ...)
0赞 T N 11/16/2023
总体范围也需要调整。我相信这可以设置为 ,因为其他范围都不能在此之前。 将是或等效的表达式。@range_from@previous_year_from@range_toGREATEST(@week_to, @year_to)CASE
1赞 Blowers 11/17/2023
谢谢,我会试一试,感谢您的帮助!
0赞 Blowers 11/17/2023
这很有效,再次感谢 T N,你绝对是一个传奇!