【问题标题】:Get products from a specific year获取特定年份的产品
【发布时间】:2018-11-26 01:48:46
【问题描述】:

我想选择一个产品结束日期仅为 2018 年的网站。

有些网站对产品有多个结束日期。例如,对于站点 A,对于产品 P1,将有多个结束日期,2018、2019、2020。我想要一个产品结束日期为 2018 的站点

┌──────┬────────┬──────────┐ │ 网站 │产品│ EndDate │ ├──────┼────────┼──────────┤ │ A │ P1 │ 2018 │ │ A │ P2 │ 2018 │ │ A │ P1 │ 2019 │ │ B │ P2 │ 2018 │ │ B │ P1 │ 2018 │ │ B │ P2 │ 2019 │ │ A │ P1 │ 2018 │ │ C │ P2 │ 2018 │ │ C │ P1 │ 2019 │ │ C │ P2 │ 2020 │ └──────┴────────┴──────────┘

根据样本数据,我需要的结果是:

第二排,A P2 2018 第 5 行,B P1 2018

我写的查询什么也没给出,我知道是错的,但如果你想看一下:

select * from utk1
where EndDate not in (Select * from utk1 where EndDate = '2018') 
AND   EndDate not in (Select * from utk1 where EndDate = '2019')

【问题讨论】:

  • 您的数据看起来完全一样吗?或者这只是一个简化的例子?那么您想要所有结束日期为 2018 年的产品吗?
  • 它有相同类型的列,我简化了一点。我想要产品结束日期为 2018 年的网站,但问题是某些网站有多个相同产品的结束日期,例如 2019 年、2020 年。那么,如何仅获取合同结束日期为 2018 年的网站
  • 也许我不明白,但它只是选择 * From ukt1 where EndDate in ('2018') 并且多年来只需选择 * From ukt1 where EndDate in ('2018', '2019' , '20xx')
  • 您应该在问题中包含示例数据和期望的结果。
  • 不应该为样本数据发布图片。它应该是文本,因此(还)不能发布图像的能力不是问题。数据图像通常没有帮助,因为其他用户无法与它们交互,或复制数据以进行测试。除非您希望其他用户手动输入您的所有数据?你不应该;)

标签: sql sql-server


【解决方案1】:

你可以试试下面的

WITH cte (site, product, enddate) 
AS (
    SELECT site, product, MAX(enddate)
    FROM utk1
    GROUP BY site, product
)
SELECT site, product, enddate
FROM cte
WHERE enddate = 2018

编辑

正在为每个站点和产品组合创建一组/cte,并为其最大结束日期。之后只考虑那些结束日期为 2018 的。
例如。对于站点 B 产品 P1,最大/最高结束日期为 2019 年,这导致该行未被考虑。对于站点 B P2,最大结束日期为 2018 年,因此该行是最终结果的一部分。

【讨论】:

  • 我认为它有效,但请您对此稍作解释。我需要了解它背后的逻辑。
  • 非常感谢您的帮助。
【解决方案2】:
select * from utk1
group by site,product
having max(EndDate) ='2018';

【讨论】:

  • 感谢您的帮助。
  • 请解释您的答案,以便其他有类似问题的用户发现它有帮助。
  • 我还没有看到 OP 的数据,但我怀疑这会起作用。 EndDate 不在您的 GROUP BY 中,而您有一个 SELECT *,因此您将收到关于返回不在聚合函数或 GROUP BY 中的列的错误。
  • @Larnu,在 5.7.5 之前使用 MySQL,尽管我同意你的观点,这样做是糟糕且无效的标准 SQL。 MySQL 终于解决了这个问题,starting with MySQL 5.7.5, the ONLY_FULL_GROUP_BY SQL mode is enabled by default.
  • @RacilHilan 这是一个 SQL Server 问题。 T-SQL 的语法可能与 MySQL 使用的 SQL 完全不同。
【解决方案3】:

你的方法没问题。你只需要正确的in 逻辑:

select *
from utk1
where site in (Select site from utk1 where EndDate = '2018')  and
      site not in (Select site from utk1 where EndDate >= '2019');

注意:我真的不相信您将年份存储为字符串。因此,您应该省去单引号。混合类型是一种不好的做法。 (如果值确实是字符串,请在下面添加单引号。)

如果您希望在产品级别使用此功能,请使用exists

select u.*
from utk1
where not exists (select 1
                  from utk1 u2 
                  where u2.site = u.site and u2.product = u.product and
                        u2.enddate >= 2019
                 ) and
      exists (select 1
              from utk1 u2 
              where u2.site = u.site and u2.product = u.product and
                    u2.enddate = 2018
             ) ;

不过,我认为更好的方法是聚合:

select site, product
from utk1
group by site, product
having max(enddate) = 2018;

这将为您提供 2018 年结束的 site/product 对。根据 cmets,这似乎是对该问题的最合理解释。

【讨论】:

  • @Man 。 . .你的评论没有意义。你能详细说明一下吗?
  • 前 2 个解决方案现在运行良好,但是当年底将是 2020 年及以上时,您必须添加另一个条件,这不是一个好主意
  • 是的,它给了我 5 行。
  • 非常感谢大家。我真的很感谢你的帮助。我想不出任何解决办法。你们太棒了。
  • 戈登,男人是对的。他的意思是你的前两个解决方案不包括 2019 年,但接下来的几年,比如 2020 年呢?而不是where EndDate = '2019',您需要使用不好的IN('2019', '2020', …),或者您需要使用> 并将varchar 年份转换为数字。您的最后一个解决方案适用于问题中的示例数据,但如果有像 2017 年这样的前几年,则不能。您需要像我在回答中所做的那样添加条件 COUNT(DISTINCT EndDate) = 1
【解决方案4】:

如果您只想要 2018 年的产品而没有其他年份,则需要添加条件 count 为 1:

SELECT site, product, MAX(EndDate) AS EndDate
FROM utk1
GROUP BY site, product
HAVING MAX(EndDate) = '2018'
   AND COUNT(DISTINCT EndDate) = 1;

注意:从您的问题来看,EndDate 似乎是varchar。如果这不正确并且它是一个数字,则将= '2018' 更改为= 2018(删除引号)。此答案还假设 2018 年之前可能有几年。如果不是这种情况,则不需要最后一行,可以删除。

【讨论】:

  • 谢谢。一个问题可以有多种解决方案,这真是太棒了。
【解决方案5】:

你应该试试这个

Select * from (
SELECT site, product, MAX(enddate) as enddate
FROM utk1 
GROUP BY site, product
)a where enddate = '2018'

【讨论】:

    【解决方案6】:

    您的问题不够清楚,因为您在 2018 年询问了带有 EndDate 的产品,并且示例中的 EndDate 列有多个 2018 条目,而在预期结果中您只选择了两个条目而没有提及获得预期输出(或记录模式)。换句话说,你给社区一个需要解决的难题(或者我的看法)。

    无论如何,从给定的输出中,我猜您需要获取 2018 年内列出的网站产品。

    因此,(如果我的分析技能仍然有效),从给定的输出中,选择了第二行和第五行,因为它们之前的行是同一年(2018 年)。

    如果是这种情况,您可能需要考虑 LAG()LEAD() 函数,它们对您的情况很有用。 您可以使用这些功能添加一些起点和终点,以便进一步过滤。

    在您的示例中,我使用了ROW_NUMBER() 函数(为简单起见)。 输出可能因实际数据而异,因此您需要检查并确保输出正确,如果您看到一些不正确的数据,那么 LAG() 或 LEAD() 将是您的解决方案。

    这是ROW_NUMBER()的解决方案

    ;WITH CTE AS(
    SELECT 
        *,
        ROW_NUMBER() OVER(PARTITION BY [site] ORDER BY [site]) AS RN
    FROM YourTable
    ) 
        SELECT
            [site], 
            product, 
            YEAR(EndDate)
        FROM CTE 
        WHERE 
            YEAR(EndDate) = 2018
        AND RN = 2
        ORDER BY [site]
    

    这里是LAG()的解决方案(获取以前的记录)

    ;WITH CTE AS(
    SELECT 
        [site], 
        product,
        EndDate AS StartDate, 
        LAG(EndDate) OVER(PARTITION BY [site] ORDER BY [site]) AS EndDate
    FROM YourTable
    ) 
        SELECT
            [site], 
            product, 
            YEAR(EndDate)
        FROM CTE 
        WHERE 
            YEAR(StartDate)  = 2018
        AND YEAR(EndDate)    = 2018
        ORDER BY [site]
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-12-04
      • 2021-11-07
      • 2017-11-06
      相关资源
      最近更新 更多