【问题标题】:T-SQL: SELECT posts where trend is downwards on two time periodsT-SQL:选择两个时间段趋势下降的帖子
【发布时间】:2018-05-23 22:58:27
【问题描述】:

我想避免在表格上进行子选择来比较两个时期以及趋势是否下降。

此选择获取一个周期的百分比

SELECT user, (SUM(value1)/SUM(value2)) AS percentage1
FROM table
WHERE (date BETWEEN @start1 AND @end1)
GROUP BY user
ORDER BY 2

这个查询得到了我想要的结果,但是效率不是很高,因为有超过 1 亿行。

SELECT t1.user, (SUM(t1.value1)/SUM(t1.value2)) AS percentage1,
(SELECT (SUM(t2.value1)/SUM(t2.value2)) AS percentage2
FROM table AS t2
WHERE t2.userID = t1.userID
AND (t2.date BETWEEN @start2 AND @end2)
)
FROM table AS t1
WHERE (t1.date BETWEEN @start1 AND @end1)
AND (SUM(t1.value1)/SUM(t1.value2)) < (SELECT (SUM(t2.value1)/SUM(t2.value2))
FROM table AS t2
WHERE t2.userID = t1.userID
AND (t2.date BETWEEN @start2 AND @end2)
)
GROUP BY t1.user

有没有更好的方法来做到这一点?一种解决方案可能是只有一个日期时间段,然后按月(日期)、年(日期)分组并与上个月进行比较,而不是有两个确切的日期。但是按月和年分组只会为每个用户提供几行,我想避免这种情况。

只想要一个像这样干净的结果:

Adam, 43%, 47%
Lisa, 22%, 25%
John, 18%, 34%

排除这样的行,因为趋势百分比较低

Bill, 24%, 18%
Nina, 84%, 56%

SQL-Server 2016 Enterprise 是数据库。

【问题讨论】:

  • 样本数据会很棒她,并定义你所有的变量是什么
  • Addeladde 转到 sqlfiddle.com 并设置一个模式供我们使用。您没有提供大量信息或数据集进行评估。

标签: sql sql-server tsql sql-server-2016


【解决方案1】:

你可以试试这个。

SELECT G1.user, G1.percentage1, G2.percentage2 
FROM 
    ( SELECT t1.user, t1.userID
        (SUM(t1.value1)/SUM(t1.value2)) AS percentage1,
      FROM table AS t1
      WHERE 
        (t1.date BETWEEN @start1 AND @end1)
      GROUP BY t1.user, t1.userID
    ) AS G1
    INNER JOIN (
        SELECT t2.userID, (SUM(t2.value1)/SUM(t2.value2)) AS percentage2
        FROM table AS t2
        WHERE 
            (t2.date BETWEEN @start2 AND @end2)
        GROUP BY t2.userID
    ) AS G2 ON G1.userID = G2.userID
WHERE 
    G1.percentage1 < G2.percentage2

但是如果你只想从表格中选择一个,那么你也可以试试这个。

DECLARE @start DATE
DECLARE @end DATE

SET @start = CASE WHEN @start1 < @start2 THEN @start1 ELSE @start2 END
SET @end = CASE WHEN @end1 > @end2 THEN @end1 ELSE @end2 END

SELECT * FROM (
    SELECT t.userID, 
        SUM( CASE WHEN t.date BETWEEN @start1 AND @end1 THEN t.value1 END ) / SUM( CASE WHEN t.date BETWEEN @start1 AND @end1 THEN t.value2 END ) AS percentage1, 
        SUM( CASE WHEN t.date BETWEEN @start2 AND @end2 THEN t.value1 END ) / SUM( CASE WHEN t.date BETWEEN @start2 AND @end2 THEN t.value2 END ) AS percentage2, 
    FROM table AS t
    WHERE 
        (t.date BETWEEN @start AND @end)
    GROUP BY t.userID
) AS SQ WHERE percentage1 < percentage2

【讨论】:

  • 这是两个选择语句,这是我想要避免的。
  • 我添加了一个选择版本。
【解决方案2】:

我们可以尝试使用 CTE 方法,如果将来需要,可以提供更高的可读性和灵活的修改。我已将索引添加到 RequiredDate 列以提高性能。希望对您有所帮助。

IF OBJECT_ID('dbo.InputUsers') IS NULL
BEGIN
CREATE TABLE dbo.InputUsers (
UserNameID INT NOT NULL,
UserName NVARCHAR(MAX),
RequiredDate DATETIME,
Value1 DECIMAL,
Value2 DECIMAL
)
CREATE NONCLUSTERED INDEX IX_Users_RequiredDate   
    ON dbo.InputUsers (RequiredDate);   
END

DECLARE @Start1 NVARCHAR(20), @End1 NVARCHAR(20), @Start2 NVARCHAR(20), @End2 NVARCHAR(20)
SET @Start1 = '2018-05-26'
SET @End1 = '2018-05-27'

SET @Start2 = '2018-05-28'
SET @End2 = '2018-05-29'

INSERT INTO InputUsers(UserNameID, UserName, RequiredDate, Value1, Value2) VALUES
(1, 'Adam', '2018-05-29', 13, 25),
(1, 'Adam', '2018-05-28', 12, 25),
(1, 'Adam', '2018-05-27', 11, 25),
(1, 'Adam', '2018-05-26', 10, 25),

(2, 'Lisa', '2018-05-29', 19, 25),
(2, 'Lisa', '2018-05-28', 18, 25),
(2, 'Lisa', '2018-05-27', 17, 25),
(2, 'Lisa', '2018-05-26', 16, 25),

(3, 'John', '2018-05-29', 16, 25),
(3, 'John', '2018-05-28', 17, 25),
(3, 'John', '2018-05-27', 18, 25),
(3, 'John', '2018-05-26', 19, 25),

(4, 'Bill', '2018-05-29', 10, 25),
(4, 'Bill', '2018-05-28', 11, 25),
(4, 'Bill', '2018-05-27', 12, 25),
(4, 'Bill', '2018-05-26', 13, 25)

;WITH PercentageValues1 AS (SELECT UserNameID, UserName, SUM(Value1)*100 / SUM(Value2) AS Percentage
FROM dbo.InputUsers
WHERE RequiredDate >= @Start1 AND RequiredDate <= @End1
GROUP BY UserNameID, UserName
),
PercentageValues2 AS (SELECT UserNameID, UserName, SUM(Value1)*100 / SUM(Value2) AS Percentage
FROM dbo.InputUsers
WHERE RequiredDate >= @Start2 AND RequiredDate <= @End2
GROUP BY UserNameID, UserName
)
SELECT pv2.UserName, pv1.Percentage, pv2.Percentage
FROM PercentageValues2 pv2
LEFT JOIN PercentageValues1 pv1 ON 
pv2.UserNameID = pv1.UserNameID
WHERE pv2.Percentage > pv1.Percentage

【讨论】:

  • 使用单个 select 语句来解决这个问题可能会很有挑战性。也许试试上面的代码,让我知道性能。
猜你喜欢
  • 1970-01-01
  • 2014-07-30
  • 1970-01-01
  • 1970-01-01
  • 2020-02-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多