列出按价格排序的5种最便宜的玩具(Postgres)

问题描述 投票:-3回答:1

如果我们每次都交付每个玩具,我想要一个价格更高的5个玩具的清单,按降序排列。

例如,我有一个价值600欧元的Ipad,并由1号,2号和3号小孩请求。现在,我有一个任天堂,花费300欧元,要求3次(孩子1次1次,孩子3次2次) )。我有另一个玩具(笔记本电脑),花费360欧元,要求8次(儿童2次2次,儿童3次6次)。然后,我必须看到:

  1. 笔记本电脑,因为要求8次,成本360€(总共8 * 360€= 2880€)
  2. Ipad因为要求3次而且花费600欧元(总共3 * 600€= 1800€)
  3. 任天堂

当我有这个,我想看到孩子的数据更多次请求相同的玩具,例如,在任天堂的情况下我想看到关于孩子2的信息。在笔记本电脑的情况下,我想看到关于孩子3的信息。

我创建这种类型:

CREATE TYPE ToysList AS (
t_Toy_name VARCHAR(255),
t_Price REAL,
t_Times_requested INTEGER,
t_Total_amount_money REAL,
t_Child_name VARCHAR(255),
t_Child_times_request SMALLINT,
t_Child_address VARCHAR(255),
t_Number_Siblings SMALLINT);

表格如下:

CREATE TABLE CHILD(
child_id SMALLINT,
child_name VARCHAR(255) NOT NULL,
birth_date DATE NOT NULL,
gender VARCHAR(255) NOT NULL,
address VARCHAR(255),
city VARCHAR(255),
CONSTRAINT PK_CHILD PRIMARY KEY(child_id),
CONSTRAINT VALID_GENDER CHECK (gender IN ('m', 'f')),
CONSTRAINT VALID_DATE CHECK (birth_date <= now())
);

CREATE TABLE letter (
letter_id SMALLINT NOT NULL,
arrival_date DATE DEFAULT now() NOT NULL,
number_toys INTEGER NOT NULL,
child_id SMALLINT,
CONSTRAINT valid_child_id CHECK ((child_id IS NOT NULL)),
CONSTRAINT PK_LETTER PRIMARY KEY(letter_id),
CONSTRAINT CHILD_FK FOREIGN KEY (child_id) REFERENCES CHILD(child_id)
);

CREATE TABLE SIBLING(
child_id1 SMALLINT,
child_id2 SMALLINT,
CONSTRAINT PK_SIBLING PRIMARY KEY(child_id1, child_id2),
CONSTRAINT CHILD1_FK FOREIGN KEY (child_id1) REFERENCES CHILD(child_id),
CONSTRAINT CHILD2_FK FOREIGN KEY (child_id2) REFERENCES CHILD(child_id)
);

CREATE TABLE TOY(
toy_id SMALLINT,
toy_name VARCHAR(255) NOT NULL,
price REAL NOT NULL,
toy_type VARCHAR(255) NOT NULL,
manufacturer VARCHAR(255),
CONSTRAINT PK_TOY PRIMARY KEY(toy_id),
CONSTRAINT POSITIVE_PRICE CHECK (price > 0),
CONSTRAINT VALID_TYPE CHECK(toy_type IN ('symbolic', 'rule', 'educational', 'cooperative', 'other'))
);

CREATE TABLE WISHED_TOY(
letter_id SMALLINT,
toy_id SMALLINT,
CONSTRAINT PK_WISHED_TOY PRIMARY KEY(letter_id, toy_id),
CONSTRAINT LETTER_FK FOREIGN KEY (letter_id) REFERENCES LETTER(letter_id),
CONSTRAINT TOY_FK FOREIGN KEY (toy_id) REFERENCES TOY(toy_id)
);

这时我做了这个:

CREATE OR REPLACE FUNCTION list_top_Toys() RETURNS SETOF ToysList AS $$

DECLARE

l_Toy_name  VARCHAR(255);   
l_Price     REAL;       
l_Times_requested   INTEGER;--total times requested for this toy
l_Total_amount_money    REAL;   --total times requested * price toy
l_Child_name    VARCHAR(255);   
l_Child_times_request   SMALLINT;   --times request for the child
l_Child_address VARCHAR(255);
l_Number_Siblings   SMALLINT;

l_toy_id    INTEGER;
l_child_id  INTEGER;
l_letter_id INTEGER;

returnset ToysList;

BEGIN

FOR l_toy_id, l_Toy_name, l_Times_requested, l_Total_amount_money
IN SELECT t.toy_id, t.toy_name, COUNT(*), SUM(price) AS totalAmountMoney
    FROM toy t INNER JOIN wished_toy WT ON t.toy_id = WT.toy_id
    GROUP BY t.toy_id, t.toy_name
    ORDER BY totalAmountMoney DESC, t.toy_name
    LIMIT 5
LOOP
    returnset.t_Toy_name = l_Toy_name;
    returnset.t_Times_requested = l_Times_requested;
    returnset.t_Total_amount_money = l_Total_amount_money;

    SELECT c.child_id, c.child_name, c.address, SUM(L.number_toys) AS totalToys
    INTO l_child_id, l_Child_name, l_Child_address, l_Child_times_request
    FROM child c 
        INNER JOIN letter L ON c.child_id = L.child_id
        INNER JOIN wished_toy WIS ON WIS.letter_id = L.letter_id
    WHERE c.child_id = l_child_id
    GROUP BY c.child_id, c.child_name
    ORDER BY totalToys DESC
    LIMIT 1;

    returnset.t_Child_name = l_Child_name;
    returnset.t_Child_address = l_Child_address;
    returnset.t_Child_times_request = l_Child_times_request;

    SELECT COUNT(s.child_id2) AS numberSiblings
    INTO l_Number_Siblings
    FROM sibling s
        INNER JOIN child c1 ON c1.child_id = s.child_id1
    WHERE s.child_id1 = l_child_id
    LIMIT 1;

    returnset.t_Number_Siblings = l_Number_Siblings;

return next returnset; 

END LOOP; 

END; 

$$LANGUAGE plpgsql; 
COMMIT;

谁能说我做错了什么?

谢谢,

sql postgresql
1个回答
1
投票

您的函数返回setof类型的数据。所以,只需从它的结果中选择,如下所示:

select * from list_top_Toys();

之后,您可以使用结果来操作,因为它是表格。但是,正如我所看到的,这个功能需要更多的改变。

第二个查询在每个LOOP迭代中给出相同的结果,因此我将其更改为反映第一个SELECT的结果,并使Letters表成为查询中的前导。

首先,为什么要按toy_name分组 - 只需要由toy_id分组。此外,group by child_name(在第一个内部查询中)是多余的。我会在结果集中包含toy_id,它可能在以后的计算中很有用。另外,你没有像你在帖子中说的那样设置玩具价格,所以首先SELECT必须有玩具的价格。

所以,我的函数版本将是:

CREATE OR REPLACE FUNCTION list_top_Toys()
   RETURNS SETOF ToysList
   AS $$

DECLARE
   l_Toy_name  VARCHAR(255);   
   l_Price     REAL;       
   l_Times_requested   INTEGER;--total times requested for this toy
   l_Total_amount_money    REAL;   --total times requested * price toy
   l_Child_name    VARCHAR(255);   
   l_Child_times_request   SMALLINT;   --times request for the child
   l_Child_address VARCHAR(255);
   l_Number_Siblings   SMALLINT;

   l_toy_id    INTEGER;
   l_child_id  INTEGER;
   l_letter_id INTEGER;

   returnset ToysList;

BEGIN
   FOR l_toy_id, l_Toy_name, l_Price, l_Times_requested, l_Total_amount_money
   IN SELECT t.toy_id, t.toy_name, t.price, COUNT(*), SUM(price) AS totalAmountMoney
      FROM toy t
      INNER JOIN wished_toy WT ON t.toy_id = WT.toy_id
      GROUP BY t.toy_id
      ORDER BY totalAmountMoney DESC, t.toy_name
      LIMIT 5
   LOOP
      returnset.t_Toy_name = l_Toy_name;
      returnset.t_Price = l_price;
      returnset.t_Times_requested = l_Times_requested;
      returnset.t_Total_amount_money = l_Total_amount_money;

      SELECT c.child_id, c.child_name, c.address, SUM(L.number_toys) AS totalToys
      INTO l_child_id, l_Child_name, l_Child_address, l_Child_times_request
      FROM letter L
         INNER JOIN child c ON c.child_id = L.child_id
         INNER JOIN wished_toy WIS ON WIS.letter_id = L.letter_id
      WHERE wis.toy_id = l_toy_id
      GROUP BY c.child_id, c.child_name
      ORDER BY totalToys DESC
      LIMIT 1;

      returnset.t_Child_name = l_Child_name;
      returnset.t_Child_address = l_Child_address;
      returnset.t_Child_times_request = l_Child_times_request;

      SELECT COUNT(s.child_id2) AS numberSiblings
      INTO l_Number_Siblings
      FROM sibling s
         INNER JOIN child c1 ON c1.child_id = s.child_id1
      WHERE s.child_id1 = l_child_id
      LIMIT 1;

      returnset.t_Number_Siblings = l_Number_Siblings;

   return next returnset; 

   END LOOP; 
END; 
$$LANGUAGE plpgsql; 

我没有触摸兄弟姐妹查询。

© www.soinside.com 2019 - 2024. All rights reserved.