简体   繁体   English

从 SQL 服务器到 PostgreSQL 的 T-SQL 存储过程

[英]T-SQL stored procedure from SQL server to PostgreSQL

For a bit of context: I've written a stored procedure that uses two tables, products ( product_id , product_name, description, price, category_id) and supplies ( shipment_id , suppliers_id, product_id (FK to products ), supply_date, quantity).对于一些上下文:我编写了一个使用两个表的存储过程, productsproduct_id 、product_name、description、price、category_id)和supplies (shipping_id、suppliers_id、product_id(FK 到products )、 supply_date 、数量)。

The procedure takes a product_id and prints the description and certain info about the product's supply within the give time range (from date1 to date2).该过程采用product_id并在给定时间范围内(从 date1 到 date2)打印有关产品供应的描述和某些信息。

This is the T-SQL code:这是 T-SQL 代码:

CREATE OR ALTER PROCEDURE productInfo
    (@product_id INT,
     @date1 DATE,
     @date2 DATE)
AS
BEGIN
    DECLARE @description VARCHAR(100),
            @shipment_id INT, 
            @supply_date DATE, 
            @quantity INT;

    DECLARE product_cursor CURSOR LOCAL FOR
        SELECT description 
        FROM products 
        WHERE product_id = @product_id

    OPEN product_cursor;

    FETCH NEXT FROM product_cursor INTO @description

    CLOSE product_cursor
    
    DECLARE product_supply_cursor CURSOR LOCAL FOR 
        SELECT shipment_id, supply_date, quantity
        FROM supplies
        WHERE product_id = @product_id

    OPEN product_supply_cursor;

    FETCH NEXT FROM product_supply_cursor INTO @shipment_id, @supply_date, @quantity;

    WHILE @@FETCH_STATUS = 0
    BEGIN
        IF @supply_date >= @date1 AND @supply_date <= @date2
        BEGIN
            PRINT 'DESCRIPTION: ' + @description
            PRINT 'SHIPMENT_ID: ' + STR(@shipment_id)
            PRINT 'SUPPLY_DATE: ' + convert(varchar, @supply_date, 23)
            PRINT 'QUANTITY: ' + STR(@quantity)
            PRINT ' '
        END;

        FETCH NEXT FROM product_supply_cursor INTO @shipment_id, @supply_date, @quantity;
    END;

    CLOSE product_supply_cursor;
END;

Obviously this procedure doesn't run in pgSQL and I have no experience on the matter so I'd like either a translation of this code or (if I'm asking too much) a hint about what things would have to change ( syntax or logic wise) to fit pgSQL language.显然,这个过程不能在 pgSQL 中运行,而且我在这件事上没有经验,所以我想要这段代码的翻译,或者(如果我问得太多)关于需要改变什么的提示(语法或逻辑明智)以适应 pgSQL 语言。

The SQL Server code is extremely convoluted to begin with. SQL 服务器代码一开始就非常复杂。 The use of cursors and the slow and inefficient (nested.) row-by-row processing can be simplified to a single SELECT statement that joins the two tables.游标的使用以及缓慢且低效的(嵌套)逐行处理可以简化为连接两个表的单个 SELECT 语句。 Doing the range check on the two dates inside the cursor loop is extremely efficient, It is much better to apply that directly in the WHERE clause of the SELECT statement, so that you don't have to iterate over 10 million rows.对 cursor 循环中的两个日期进行范围检查非常有效,最好直接在 SELECT 语句的 WHERE 子句中应用它,这样您就不必迭代超过 1000 万行。 just to show 5.只是为了显示 5。

A naive migration would do something like this:一个天真的迁移会做这样的事情:

create procedure print_product_info(p_product_id int, p_date1 date, p_date2 date)
as
$$
declare
  l_row record;
begin
  for l_row in SELECT p.description, s.shipment_id, s.supply_date, s.quantity
               FROM supplies s
                 JOIN products p ON p.product_id = s.product_id
               WHERE p.product_id = p_product_id
                 AND s.supply_date >= p_date1
                 AND s.supply_date <= p_date2
  loop
    raise notice 'DESCRIPTION: %', l_row.description;
    raise notice 'SHIPMENT_ID: %', l_row.shipment_id;
    raise notice 'SUPPLY_DATE: %', to_char(l_row.supply_date, 'yyyy-mm-dd');
    raise notice 'QUANTITY: %', l_row.quantity;
  end loop;
end;
$$
language plpgsql;

However, this is not how one would do this in Postgres.但是,这不是在 Postgres 中这样做的方式。 Results should not be "printed", but simply "returned" by a function (procedures aren't intended to return things).结果不应“打印”,而应由 function 简单地“返回”(程序并非旨在返回内容)。

The proper way to implement this in Postgres is a set-returning function:在 Postgres 中实现这一点的正确方法是返回集合 function:

create function get_product_info(p_product_id int, p_date1 date, p_date2 date)
  returns table(description text, shipment_id int, supply_date date, quantity int)
as
$$
  SELECT p.description, s.shipment_id, s.supply_date, s.quantity
  FROM supplies s
   JOIN products p ON p.product_id = s.product_id
  WHERE p.product_id = p_product_id
   AND s.supply_date >= p_date1
   AND s.supply_date <= p_date2
$$
language sql;

To display the data, use:要显示数据,请使用:

select *
from get_product_info(42, date '2020-01-07', '2020-01-12');

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM