列出最便宜的5件玩具(Postgres)

时间:2017-12-16 20:15:24

标签: sql postgresql

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

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

  1. 笔记本电脑,因为要求8次,费用为360欧元(总共8 * 360€= 2880€)
  2. Ipad因为要求3次而且花费600欧元(总共3 * 600€= 1800€)
  3. 任天堂
  4. 当我有这个时,我想看到孩子的数据更多次请求相同的玩具,例如,在任天堂的情况下我想看到关于孩子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;
    

    有谁能说我做错了什么?

    谢谢,

1 个答案:

答案 0 :(得分: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; 

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