我收到错误“子查询必须只返回一列”,但是当我选择curProd时,我尝试使用不同的东西来返回第一条记录。
我正在使用这个功能,但据我所知,我得到了错误:
curProd := (
SELECT "KeysForSale".*
FROM "KeysForSale"
WHERE row_STab.product_id = "KeysForSale".product_id AND (("KeysForSale".begin_date < payment_date AND "KeysForSale".end_date > payment_date) OR ("KeysForSale".discounted_price IS NULL))
ORDER BY "KeysForSale".discounted_price ASC NULLS LAST
LIMIT 1
);
所有功能是:
CREATE FUNCTION "paymentRun"(buyer_id integer, payment_date DATE, payMethod paymentMethod, paid_amount double precision, payDetails text) RETURNS VOID AS
$$
DECLARE
row_STab "SearchTable"%rowtype;
curProd "KeysForSale"%rowtype;
totalPrice double precision;
returnedPID integer;
BEGIN
--For each entry in the search table
FOR row_STab IN
(
SELECT *
FROM "SearchTable"
)
LOOP
--We retrieve the associated product info, together with an available key
curProd := (
SELECT "KeysForSale".*
FROM "KeysForSale"
WHERE row_STab.product_id = "KeysForSale".product_id AND (("KeysForSale".begin_date < payment_date AND "KeysForSale".end_date > payment_date) OR ("KeysForSale".discounted_price IS NULL))
ORDER BY "KeysForSale".discounted_price ASC NULLS LAST
LIMIT 1
);
--Either there is no such product, or no keys for it
IF curProd IS NULL THEN
RAISE EXCEPTION 'Product is not available for purchase.';
END IF;
--Product's seller is the buyer - we can't let that pass
IF curProd.user_id = buyer_id THEN
RAISE EXCEPTION 'A Seller cannot purchase their own product.';
END IF;
--Fill in the rest of the data to prepare the purchase
UPDATE "SearchTable"
SET "SearchTable".price = (
CASE curProd.discounted_price IS NOT NULL -- if there was a discounted price, use it
WHEN TRUE THEN curProd.discounted_price
ELSE curProd.price
END
), "SearchTable".sk_id = curProd.sk_id
WHERE "SearchTable".product_id = curProd.product_id;
END LOOP;
--Get total cost
totalPrice := (
SELECT SUM("SearchTable".price)
FROM "SearchTable"
);
--The given price does not match the actual cost?
IF totalPrice <> paid_amount THEN
RAISE EXCEPTION 'Payment does not match cost!';
END IF;
--Create a purchase while keeping it's ID for register
INSERT INTO "Purchases" (purchase_id, final_price, user_id, paid_date, payment_method, details)
VALUES (DEFAULT, totalPrice, buyer_id, payment_date, payMethod, payDetails)
RETURNING purchase_id INTO returnedPID;
--For each product we wish to purchase
FOR row_STab IN
(
SELECT *
FROM "SearchTable"
)
LOOP
INSERT INTO "PurchasedKeys"(sk_id, purchase_id, price)
VALUES (row_STab.sk_id, returnedPID, row_STab.price);
UPDATE "SerialKeys"
SET "SerialKeys".user_id = buyer_id
WHERE row_STab.sk_id = "SerialKeys".sk_id;
END LOOP;
END
$$
LANGUAGE 'plpgsql' ;
提前谢谢
答案 0 :(得分:0)
由于问题答案不正确,我提供的答案超出了评论范围。您想要的代码是:
curProd := (
SELECT "KeysForSale"
FROM "KeysForSale"
WHERE row_STab.product_id = "KeysForSale".product_id AND (("KeysForSale".begin_date < payment_date AND "KeysForSale".end_date > payment_date) OR ("KeysForSale".discounted_price IS NULL))
ORDER BY "KeysForSale".discounted_price ASC NULLS LAST
LIMIT 1
);
区别在于缺少.*
。你的版本返回了一堆列 - 这是你得到的错误。您想要返回单个记录。表名提供了这个。
我也认为括号会产生同样的效果:
SELECT ("KeysForSale".*)
答案 1 :(得分:0)
对于这种情况,您不应该使用语法:
var := (SELECT ..).
首选应为SELECT INTO
:
SELECT * INTO curProd FROM ...
语法SELECT tabname FROM tabname
是PostgreSQL专有的,虽然它运行良好,但最好不要使用,因为没有更深入的PostgreSQL知识的所有人都不可读。
因为PL / pgSQL不是区分大小写的语言,所以不建议使用驼峰(最好使用蛇案例)。
如果可能,请不要使用ISAM风格:
FOR _id IN
SELECT id FROM tab1
LOOP
SELECT * INTO r FROM tab2 WHERE tab2.id = _id
它明显慢于连接(对于更多迭代)
FOR r IN
SELECT tab2.*
FROM tab1 JOIN tab2 ON tab1.id = tab2.id
LOOP
..
周期对性能不利。这部分不是很好:
FOR row_STab IN ( SELECT * FROM "SearchTable" ) LOOP INSERT INTO "PurchasedKeys"(sk_id, purchase_id, price) VALUES (row_STab.sk_id, returnedPID, row_STab.price); UPDATE "SerialKeys" SET "SerialKeys".user_id = buyer_id WHERE row_STab.sk_id = "SerialKeys".sk_id; END LOOP;
可能的解决方案:
改为使用批量命令:
INSERT INTO "PurchasedKeys"(sk_id, purchase_id, price)
SELECT sk_id, returnedPID, price
FROM "SearchTable"; -- using case sensitive identifiers is way to hell
UPDATE "SerialKeys"
SET "SerialKeys".user_id = buyer_id
FROM "SearchTable"
WHERE "SearchTable".sk_id = "SerialKeys".sk_id;
ISAM样式的性能较低取决于迭代次数。对于低迭代,它并不重要,因为更高的数字是死亡。