テーブルmytable(id、 "someLongURI"、status、 "userId")と有効なクエリがあります。
UPDATE mytable
SET status = 'IN_WORK'
WHERE "someLongURI" IN (
SELECT "someLongURI"
FROM mytable
WHERE status = 'UNUSED'
AND pg_try_advisory_xact_lock(id)
ORDER BY id ASC
LIMIT 1
FOR UPDATE
)
RETURNING id, "someLongURI";
しかし、ここで「userId」パラメーターを確認し、これに基づいて既存の行を選択するか、更新する(そして更新された行を受け取る)必要があります。そのような何か(MySQLではこれはうまくいくでしょう):
IF NOT EXISTS (
SELECT 1
FROM mytable tbl
WHERE tbl."userId" = 123
)
THEN
UPDATE mytable tbl
SET tbl.status = 'IN_WORK',
tbl."userId" = 123
WHERE tbl."someLongURI" IN (
SELECT "someLongURI"
FROM tbl.mytable
WHERE tbl.status = 'UNUSED'
AND pg_try_advisory_xact_lock(id)
ORDER BY id ASC
LIMIT 1
FOR UPDATE
)
RETURNING tbl.id, tbl."someLongURI";
ELSE
SELECT tbl.id, tbl."someLongURI"
FROM mytable tbl
WHERE tbl."userId" = 123;
END IF;
DO $$ BEGIN {...} END $$;で囲みましたが、うまくいきませんでした。私が最後に来たこと:
DO
RETURNS TABLE (id INT4, "someLongURI" TEXT) AS
$$
DECLARE
"_userId" INT4;
BEGIN
"_userId" = 123;
IF NOT EXISTS (
SELECT 1
FROM mytable tbl
WHERE tbl."userId" = "_userId"
)
THEN
UPDATE mytable tbl
SET tbl.status = 'IN_WORK'
tbl."userId" = "_userId"
WHERE tbl."someLongURI" IN (
SELECT "someLongURI"
FROM tbl.mytable
WHERE tbl.status = 'UNUSED'
AND pg_try_advisory_xact_lock(id)
ORDER BY id ASC
LIMIT 1
FOR UPDATE
)
RETURNING tbl.id, tbl."someLongURI";
ELSE
SELECT tbl.id, tbl."someLongURI"
FROM mytable tbl
WHERE tbl."userId" = "_userId";
END IF;
END $$;
クエリの結果を受け取るために、この匿名コードブロック内に「RETURNS」またはその他のステートメントを追加する必要がある場所を理解できません。
Postgresでは、IFステートメントを必要とせずに、単一の CTEを変更するデータ でそれを行うことができます。
WITH data AS (
SELECT tbl.id, tbl."someLongURI"
FROM mytable tbl
WHERE tbl."userId" = 123;
), changed AS (
UPDATE mytable tbl
SET tbl.status = 'IN_WORK',
tbl."userId" = 123
WHERE tbl."someLongURI" IN (
SELECT "someLongURI"
FROM tbl.mytable
WHERE tbl.status = 'UNUSED'
AND pg_try_advisory_xact_lock(id)
ORDER BY id ASC
LIMIT 1
FOR UPDATE
)
AND NOT EXISTS (SELECT * FROM data)
RETURNING tbl.id, tbl."someLongURI"
)
SELECT *
FROM changed
UNION ALL
SELECT *
FROM data
WHERE NOT EXISTS (SELECT * FROM changed);