我已为我的问题准备了an SQL Fiddle。
在文字游戏中,我运行a custom function查找用户在上一回合播放的所有单词:
无效字词的score
为NULL
(如果需要,可以更改为-1
。)
有效单词有正score
,如果有多个匹配单词,那么我只需要得分最高(并丢弃其他分数)。
例如,如果玩家玩得分为8的水平单词“ab”和得分为2的垂直单词“ab”,则该回合只得到8分。
这是我的测试表:
CREATE TABLE words(word varchar, score integer);
在这里我填写测试数据:
INSERT INTO words (word, score) VALUES
('ab', 8), -- word with higher score should be taken
('ab', 2), -- same word with lower score should be discarded
('xy', 2),
('zz', NULL); -- invalid word marked by NULL (or -1)
我可以看到
是否播放了无效的字词IF EXISTS (SELECT 1 FROM words WHERE score IS NULL) THEN
RAISE EXCEPTION 'Invalid word played';
END IF;
我可以使用GROUP BY
删除重复的字词:
SELECT word, max(score) as score FROM words GROUP BY word;
然而我的问题是:
如何将上述两个语句组合到单个SELECT
语句中,以便I:
我正在寻找单个语句,因此the custom function不会多次运行,最好没有临时表。
结果应该是这样的(我将从另一个自定义PL / pgSQL函数调用它):
DECLARE
total_user_score integer;
invalid_words_found boolean;
SELECT
....., -- how to calculate this value please?
..... -- how to calculate this value please?
INTO STRICT
total_user_score,
invalid_words_found
FROM words_check_words(....); -- avoid calling this function twice
IF invalid_words_found THEN
RAISE EXCEPTION "Invalid words found";
ELSE
UPDATE games SET user_score = user_score + total_user_score;
END IF;
答案 0 :(得分:1)
(编辑为返回invalid_words_found
的布尔值)
(已编辑为使用bool_or
汇总功能)
如果我理解正确:
with cte as (
select max(score) as score,
bool_or(score is null) as has_invalid
from words_check_words(....)
group by word
)
select coalesce(sum(score), 0) as total_user_score,
bool_or(has_invalid) as invalid_words_found
from cte
您的自定义函数只会被调用一次。
编辑:整合到您的程序中,它看起来像这样:
DECLARE
total_user_score integer;
invalid_words_found boolean;
with cte as (
select max(score) as score,
bool_or(score is null) as has_invalid
from words_check_words(....)
group by word
)
select coalesce(sum(score), 0),
bool_or(has_invalid)
INTO STRICT
total_user_score,
invalid_words_found
FROM cte;
IF invalid_words_found THEN
RAISE EXCEPTION "Invalid words found";
ELSE
UPDATE games SET user_score = user_score + total_user_score;
END IF;
答案 1 :(得分:1)
你可以这样做:
select coalesce(sum(max_score), 0) as total_user_score,
count(*) - count(max_score) as invalid_words_found
from (select max(score) as max_score
from words
group by word) x
请参阅:Sql Fiddle
这假定如果一个单词无效,它也不会出现(在另一个记录中)具有非空分数。
IF
语句需要如下所示:
IF invalid_words_found > 0 THEN
...您可以在错误消息中显示无效字的数量:
RAISE EXCEPTION '% Invalid words found!', invalid_words_found;
答案 2 :(得分:1)
select
word,
max(
case
when score is null then raise_error('Invalid word: ' || word)::int
else score
end)
from words
group by word;
raise_error
函数声明为
create function raise_error(text) returns text language plpgsql volatile as
$body$
begin
raise exception '%', $1;
end $body$;
为了使查询更加优雅,可以创建另一个通用功能:
create function assert(
p_cond boolean,
p_message text,
p_result anyelement) returns anyelement language plpgsql volatile as
$body$
begin
if p_cond then
return p_result;
else
raise exception '%', p_message;
end if;
end $body$;
查询变得更加紧凑:
select
word,
max(assert(score is not null, 'Invalid word: ' || word, score))
from words
group by word;