2017-02-11 25 views
2

Следующая заказ хранимая функция -Как перетасовать массив в PostgreSQL 9.6, а также более низкие версии?

CREATE OR REPLACE FUNCTION words_shuffle(in_array varchar[]) 
     RETURNS varchar[] AS 
$func$ 
     SELECT array_agg(letters.x) FROM 
     (SELECT UNNEST(in_array) x ORDER BY RANDOM()) letters; 
$func$ LANGUAGE sql STABLE; 

был перетасовки массив символов в PostgreSQL 9.5.3:

words=> select words_shuffle(ARRAY['a','b','c','d','e','f']); 
words_shuffle 
--------------- 
{c,d,b,a,e,f} 
(1 row) 

Но теперь после того, как я перешел на PostgreSQL 9.6.2 функция перестал работать:

words=> select words_shuffle(ARRAY['a','b','c','d','e','f']); 
words_shuffle 
--------------- 
{a,b,c,d,e,f} 
(1 row) 

Возможно, потому что ORDER BY RANDOM() прекратил работать:

words=> select unnest(ARRAY['a','b','c','d','e','f']) order by random(); 
unnest 
-------- 
a 
b 
c 
d 
e 
f 
(6 rows) 

Я ищу, пожалуйста, лучший способ перетасовать массив символов, который будет работать в новом PostgreSQL 9.6, но также и в 9.5.

Мне нужен он для my word game в разработке, который использует функции Pl/PgSQL.

UPDATE:

Ответить на Tom Lane:

Расширение СРР в TargetList происходит сейчас после ORDER BY. Таким образом, ORDER BY сортирует одну фиктивную строку, а затем после этого происходит нечувствительность . См

https://git.postgresql.org/gitweb/?p=postgresql.git&a=commitdiff&h=9118d03a8

ответ

5

В общем случае, набор функций возвращения должны быть помещены в FROM пункте:

select array_agg(u order by random()) 
from unnest(array['a','b','c','d','e','f']) u 

    array_agg 
--------------- 
{d,f,b,e,c,a} 
(1 row) 

Для the documentation (подчеркивание добавлено):

В настоящее время функции, возвращающие наборы могут также вызывать в списке выбора запроса. Для каждой строки, которую генерирует запрос сам по себе, вызывается функция, возвращающая набор, и выводимая строка создается для каждого элемента набора результатов функции. Обратите внимание, однако, что эта функция устарела и может быть удалена в будущих выпусках.

+0

Разница между предложением 'from' и' select' действительно не имеет никакого отношения к тому, почему это перестало работать. Хотя ответ правильный и правильное настроение (введите функции генерации строк в предложении 'from'), аргументация отключена. –

+0

У меня никогда не было проблем с этим, поскольку я никогда не использовал SRF в предложении SELECT. Я думаю, что нужно принять это правило, поскольку случай, описанный в вопросе, не является одной известной проблемой, вызванной неправильным использованием SRF. – klin

1

Нет сомнений в том, что это изменение, и из-за какой-то «улучшение» в оптимизатором. Учитывая, что тип документации говорит, что это работает, это расстраивает.

Однако, я хотел бы предложить, что вы не зависит от подзапроса:

SELECT array_agg(letters.x ORDER BY random()) 
FROM UNNEST(in_array) l(x); 

Это также должно работать в версиях порядка Postgres.

documentation говорит:

В качестве альтернативы, подачи входных значений из отсортированного подзапроса будет обычно работают. Например:

SELECT xmlagg(x) FROM (SELECT x FROM test ORDER BY y DESC) AS tab; 

Но этот синтаксис не допускается в стандарте SQL и не для других систем баз данных.

(я свободно признаю, что «обычно будет работать» не является гарантией. Но имея некачественные образцы кода в документации действительно вводит в заблуждение. Почему не это показывает правильный образец, используя пункт ORDER BY в агрегации функционировать?)

https://www.postgresql.org/docs/9.5/static/functions-aggregate.html