【问题标题】:Return column based on calculated value of other columns根据其他列的计算值返回列
【发布时间】:2019-04-17 23:44:13
【问题描述】:
CREATE TABLE most_prof
(
    pub_id CHAR(4) NOT NULL,
    top_profit VARCHAR(80) NOT NULL,
    date_time DATETIME,
    PRIMARY KEY (top_profit)
)

INSERT INTO most_prof (pub_id, top_profit, date_time)
    SELECT t.pub_id, t.title, t.pubdate
    FROM titles AS t 

这是作业,所以我绝不要求答案,只是一些指导! 在选择语句中,我有 t.title,我需要返回与计算的最高利润相关联的标题。所以我需要取几列,计算最高利润,并返回与之关联的标题。每个 pub_id 都有多个与之关联的标题,但我只需要一个利润最高的标题和与之关联的发布日期。

我尝试了一些方法,但我一直收到此错误

选择列表中的列“titles.pub_id”无效,因为它既不包含在聚合函数中,也不包含在 GROUP BY 子句中。

由于这是家庭作业,请不要回答,尽可能寻求指导。

编辑:

在 SELECT 语句中,t.title 返回一本书的标题,但是这必须是一个特定的标题。为了找到这一点,我需要使用表中的其他列来计算每个出版商的标题利润 - 类似于 (((price - (royalty * 1.0 / 100)) * ytd_sales) - Advance)。然后我需要用它来返回每个出版商利润最高的 1 个标题。

第二次编辑:这就是上面所说的错误

INSERT INTO most_prof(pub_id, top_profit, date_time)
    SELECT t.pub_id, (((price - (royalty * 1.0 / 100)) * ytd_sales) - 
advance), t.pubdate
    FROM titles AS t 
    GROUP BY t.title;

第三次编辑:

INSERT INTO most_prof (pub_id, top_profit, date_time)
    SELECT DISTINCT
        pub_id, MAX (((price - (royalty * 1.0 / 100)) * ytd_sales) - advance), 
        pubdate
    FROM titles
    GROUP BY pub_id

现在这将返回 pub_id、top_profit 和 pubdate:

  1. 虽然它返回正确的利润,但我需要与之关联的标题,而不是利润本身
  2. 选择 pubdate 会再次导致该聚合错误 - 似乎无法改变

编辑 4:基于评论

我已经添加了我目前所获得的屏幕截图 - 它看起来不错。如您所见,每个 pub_id 都有多个标题 - 我怎样才能只返回 3 个 pub_id 中最有利可图的标题??

【问题讨论】:

  • 您的 SELECT 查询是否单独运行? 从标题中选择 t.pub_id、t.title、t.pubdate
  • “计算最高利润”是什么意思? Top_profit 是一个 varchar,你要计算什么?为什么要在所谓的“最高利润”中插入一个叫做“标题”的东西?
  • @HoneyBadger,我认为标题是最赚钱的酒吧名称...
  • 请添加您尝试过的代码。这可能有助于了解您的意图。
  • 谷歌如何使用GROUP BY

标签: sql sql-server ssms


【解决方案1】:

首先,我要感谢您:

这是作业,所以我绝不是在要求答案,只是一些 指导!

还有这个:

由于这是作业,请不要回答,只是寻求指导 尽你所能。

我将尝试做的是给你一些提示,引导你找到答案。

(根据给定的信息)我假设这个作业将使用聚合函数(例如 SUM()、AVG()、MIN()、MAX() ..etc)、GROUP BY、(可能是 HAVING)和订购人。

请记住,无论何时使用聚合函数,都需要指定 SELECT 下的列,并且它们不包含在 GROUP BY 子句中的聚合函数中。

所以,如果你这样做了:

SELECT  t.pub_id,  SUM(((price - (royalty * 1.0 / 100)) * ytd_sales) - advance), t.pubdate
FROM titles AS t 
GROUP BY t.title;

它会给你一个错误,因为 SELECT 子句下没有t.title。所以,正确的应该是这样的: GROUP BY t.pub_id, t.pubdate

如果你希望它按 t.title 分组,你需要这样做:

SELECT t.title,  SUM(((price - (royalty * 1.0 / 100)) * ytd_sales) - advance)
    FROM titles AS t 
    GROUP BY t.title;

如果有规定的时间段(假设您想获得每个标题最近 3 个月的利润),那么您可以使用 t.pubdate 但这将在 WHERE(或 HAVING)子句下,并且t.title 将在 SELECT 子句下。

现在,完成计算后,您需要按最高利润对结果重新排序,然后选择最高利润。有些人喜欢更容易包含两个聚合函数(比如 MIN(SUM(...)) )来获得最高或最低,这将避免他们使用 ORDER BY。

更新(基于 cmets)

由于您已经介绍了子查询,因此您非常接近答案。

运行第二个标题查询后,我可以看到所有 头衔和他们的利润,我似乎无法弄清楚如何关联 这些标题及其相应的 pub_id。假设我有 3 pub_id's - 每个 pub_id 有多个标题。我不知道怎么做 关联特定 pub_id 的 top_profit 标题,如果那样的话 有道理。

获取利润的正确方法是找到可以用来汇总利润的唯一 ID。对于您的情况,您说 pub_id 有多个 title 然后,我假设 pub_id 是主键,并且标题被分配给每个主键。 (例如,一个出版商可以出版多本书)所以你需要从所有出版的书籍中获得出版商的利润。

有了这个,您就知道您需要的是出版商而不是书籍。因此,在您的查询中,您需要将 titles 替换为 pub_id 并保持其余部分不变。这将根据pub_id 总结所有利润,这是您需要的主要要求。

如果你需要为每个出版商的书获取利润,你可以使用

SELECT t.pub_id, t.title SUM(....) as Profit
FROM  titles AS t 
GROUP BY t.pub_id, t.title; 

这就像告诉 SQL :嘿,给我每本书的出版商利润。这将为您带来每本书的利润。

但如果你这样做:

SELECT t.pub_id, SUM(....) as Profit
FROM  titles AS t 
GROUP BY t.pub_id; 

它会为您提供每个出版商的利润(这意味着如果出版商有 5 本书,则将其相加)。

因此,GROUP BY 中包含的列越多,SUM() 中的列就越详细。

如果您需要用子查询将其括起来,有不同的方法可以做到这一点,但我会给您两种方法。

方法一:

SELECT * 
FROM (
    SELECT t.pub_id, SUM(....) as Profit
    FROM  titles AS t 
    GROUP BY t.pub_id; 
) D -- alias is mandatory

方法二:

SELECT *
FROM titles t1 
JOIN (
    SELECT t.pub_id, SUM(....) as Profit
    FROM  titles AS t 
    GROUP BY t.pub_id; 
) t2 ON t1.pub_id = t2.pub_id

因此,您可以使用方法一或方法二,随心所欲。

更新(基于 cmets)#2

我已经添加了我目前所获得的屏幕截图 - 它看起来不错。 如您所见,每个 pub_id 都有多个标题 - 我怎么能 只返回 3 个 pub_id 中最赚钱的标题??

太好了,你快完成了。您需要使用名为ROW_NUMBER() 的函数根据我们的自定义条件对行进行编号。所以我们将添加这个: ROW_NUMBER() OVER(PARTITION BY t1.pub_id ORDER BY Profit DESC) AS ProfitOrder 新订单将按 t1.pub_id 进行分区,并将每个分区按利润从高到低排序(对于每个 id 组)。

我们的查询应该是这样的:

SELECT 
        t1.title
    ,   t1.pub_id
    ,   t1.pubdate
    ,   Profit
    ,   ROW_NUMBER() OVER(PARTITION BY t1.pub_id ORDER BY Profit DESC) AS ProfitOrder
    FROM titles t1 
    JOIN (
        SELECT t.pub_id, t.title, SUM(price * ytd_sales) as Profit
        FROM  titles AS t 
        GROUP BY t.pub_id 
    ) t2 ON t1.pub_id = t2.pub_id

如果您运行上面的查询,每个 pub_id 的 ProfitOrder 编号 1 将具有最高的 Profit,这将验证我们的记录是否正确排序,我们只需要使用 ProfitOrder 从每个组中获取前 3 行。 如果我们需要这样做:

SELECT 
    t1.title
,   t1.pub_id
,   t1.pubdate
,   Profit
,   ROW_NUMBER() OVER(PARTITION BY t1.pub_id ORDER BY Profit DESC) AS ProfitOrder
FROM titles t1 
JOIN (
    SELECT t.pub_id, t.title, SUM(price * ytd_sales) as Profit
    FROM  titles AS t 
    GROUP BY t.pub_id 
) t2 ON t1.pub_id = t2.pub_id
WHERE 
    ProfitOrder <= 3

它会产生错误,因为我们不能在WHERE 下使用列别名,除非我们将查询转换为子查询。因此,我们需要(再次)将此查询包含在子查询中。喜欢这个:

SELECT *
FROM (
    SELECT 
        t1.title
    ,   t1.pub_id
    ,   t1.pubdate
    ,   Profit
    ,   ROW_NUMBER() OVER(PARTITION BY t1.pub_id ORDER BY Profit DESC) AS ProfitOrder
    FROM titles t1 
    JOIN (
        SELECT t.pub_id, t.title, SUM(price * ytd_sales) as Profit
        FROM  titles AS t 
        GROUP BY t.pub_id 
    ) t2 ON t1.pub_id = t2.pub_id
) D 
WHERE 
    ProfitOrder <= 3

现在,如果输出符合您的预期,请再次验证记录。然后,您只需要使用顶部的SELECT * 并选择您只需要显示的列。 LIKE SELECT pub_id, Profit, pubdate,并将其包含在您的 INSERT 下,但请确保您匹配 INSERT 和您的 SELECT 之间的列。

【讨论】:

  • 这确实有帮助,谢谢。我真的不知道如何返回与我们计算的 top_profit 相对应的书名,以及它的 pub_id 和 pub_date。我不断收到该汇总错误。
  • @eran0801 首先考虑您的输出,输出将如何,在您的情况下,您想要显示 (title) 然后,列标题将在 SELECT 下,没有任何聚合, rest 将仅用作WHERE 下的过滤器。因此,首先,您可以开始对我的答案使用第二个查询,并开始在其之上构建其余的要求。如果您有任何困难,请告诉我,我会尽力而为。
  • @eran0801 只是我需要知道,您是否在课程中涵盖了相关查询(也称为子查询)?。
  • 当我只有 SELECT t.title 时,我会收到一个错误,因为我需要在 pub_id 和 date_time 中插入一些东西,但是在 select 语句中只有标题让我少了几个项目跨度>
  • 运行第二个标题查询后,我可以看到所有标题及其利润,但我似乎无法弄清楚如何将这些标题与其对应的 pub_id 关联起来。假设我有 3 个 pub_id - 每个 pub_id 有多个标题。如果有意义的话,我不知道如何关联特定 pub_id 的 top_profit 标题。
猜你喜欢
  • 2014-11-04
  • 2022-07-08
  • 2020-11-16
  • 2019-03-09
  • 1970-01-01
  • 2023-03-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多