根据其他列的计算值返回列

时间:2018-11-14 22:45:07

标签: sql sql-server ssms

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的select语句中,我需要返回与计算出的最高利润相关的标题。因此,我需要占用几列,计算最高利润,然后返回与之相关的标题。每个pub_id都有多个与之关联的标题,但我只需要一个利润最高的标题和与之关联的pubdate。

我尝试了一些尝试,但是我不断收到此错误

  

列“ 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和发布日期:

  1. 虽然返回正确的利润,但我需要与此相关的标题,而不是利润本身
  2. 选择pubdate会再次导致该汇总错误-似乎无法克服这一点

编辑4:基于注释 progress pic

我已经添加了到目前为止的内容的屏幕抓图-看起来不错。如您所见,每个pub_id都有多个标题-如何为三个pub_id的每个返回最赚钱的标题?

1 个答案:

答案 0 :(得分:2)

首先,我要感谢您:

  

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

这:

  

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

我将尝试做的是给您一些提示,以帮助您找到答案。

(根据给定的信息),我假设这是家庭作业,将使用聚合函数(例如SUM(),AVG(),MIN(),MAX()等),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。

更新(基于评论)

由于您已经涵盖了子查询,因此您已经很接近答案了。

  

运行第二个标题查询后,我可以看到所有   标题及其利润,我似乎无法弄清楚如何建立关联   这些标题及其相应的pub_id。可以说我有3个   pub_id-和每个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 BYSUM()中包括的更多列中进一步详细介绍。

如果您需要用子查询将其括起来,则有不同的方法来执行此操作,但我将为您提供两种方法。

方法一:

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

因此,您可以根据需要使用方法一或方法二。

更新(基于评论)#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 *并选择仅需要显示的列即可。像SELECT pub_id, Profit, pubdate,然后将其包括在INSERT下,但要确保INSERT和SELECT之间的列匹配。