PL / pgSQL: объединение значений строк в JSON-подобную строку - PullRequest
0 голосов
/ 28 декабря 2010

Я пытаюсь получить статистику игрока за последние 20 недель:

# select yw, money
from pref_money where id='OK122471020773'
order by yw desc limit 20;
   yw    | money
---------+-------
 2010-52 |  1130
 2010-51 |  3848
 2010-50 |  4238
 2010-49 |  2494
 2010-48 |   936
 2010-47 |  3453
 2010-46 |  3923
 2010-45 |  1110
 2010-44 |   185
(9 rows)

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

"2010-44:185;2010-45:1110; .... ;2010-52:1130"

Итак, я пытаюсь создать следующую процедуру PL / pgSQL:

create or replace function pref_money_stats(_id varchar)
returns varchar as $BODY$
begin

declare stats varchar;

for row in select yw, money from pref_money
    where id=_id order by yw desc limit 20 loop
        stats := row.id || ':' || row.money || ';' stats;
end loop;

return stats;
end;
$BODY$ language plpgsql;

Но я получаю синтаксическую ошибку:

ERROR:  syntax error at or near "for"
LINE 7:         for row in select yw, money from pref_money where id...

Использование PostgreSQL 8.4.6 с CentOS 5.5 Linux.

UPDATE:

Я пытаюсь выполнить всю эту конкатенацию строк с PL / pgSQL, а не с помощью скрипта PHP, потому что у меня уже есть основной оператор SQL select, который возвращает информацию о пользователе, и эта информация печатается строка за строкой как XML для моего мобильного телефона. приложение:

select u.id,
    u.first_name,
    u.female,
    u.city,
    u.avatar,
    m.money,
    u.login > u.logout as online
from pref_users u, pref_money m where
    m.yw=to_char(current_timestamp, 'YYYY-IW')
    and u.id=m.id
order by m.money desc
limit 20 offset ?

Вот скриншот мобильного приложения:

alt text

А вот выдержка из XML:

<?xml version="1.0"?>
<pref>
<user id="OK510352632290" name="ирина" money="2067" pos="1" medals="1" female="1" avatar="http://i221.odnoklassniki.ru/getImage?photoId=259607761026&amp;photoType=0" city="староконстантинов" />
<user id="OK19895063121" name="Александр" money="1912" pos="2" online="1" avatar="http://i69.odnoklassniki.ru/getImage?photoId=244173589553&amp;photoType=0" city="Сызрань" />
<user id="OK501875102516" name="Исмаил" money="1608" pos="3" online="1" avatar="http://i102.odnoklassniki.ru/res/stub_128x96.gif" city="Москва" />
.....
</pref>

Но моя проблема в том, что у меня есть еще 3 таблицы, из которых мне нужна эта статистика за последние 20 недель. Поэтому я надеюсь создать 3 процедуры, возвращающие varchars, как в моем первоначальном посте, и интегрировать их в этот оператор SQL select. Чтобы я мог добавить дополнительные атрибуты к данным XML:

<user id="OK12345" .... money_stats="2010-44:185;2010-45:1110; .... ;2010-52:1130" ..... />

Спасибо! Alex

Ответы [ 3 ]

1 голос
/ 29 декабря 2010

Агрегатные функции хороши для объединения значений:

create or replace function test
    (text, text, text)
    returns text as
    $$
        select $1 || ':' || $2 || ';' || $3
    $$
    language sql;

drop function test(text, text);
drop aggregate test(text, text) cascade;
create aggregate test(text, text)
(
    sfunc = test,
    stype = text,
    initcond = ''
);

test = # выберите тест (a :: text, b :: text) из (выберите generate_series (1,3) как a, generate_series (4,5) a с б) т;

: 1; 4: 2; 5: 3, 4: 1, 5: 2, 4: 3; 5

(я оставлю вам дело с ведущим Колином: -)

1 голос
/ 28 апреля 2011

Возможно, вы уже нашли ответ на свою проблему. Тем не менее, проблема была действительно в синтаксисе.

Проблема заключалась в том, что объявление объявлялось неправильно: оно должно появляться до начала (http://www.postgresql.org/docs/8.4/static/plpgsql-structure.html):

create or replace function pref_money_stats(_id varchar)
returns varchar as $BODY$
declare stats varchar;
begin
...

Еще одна деталь, на которую следует обратить внимание, это то, что вам нужно объявить строку как запись:

declare 
        stats varchar;
        row record;

так что это утверждение работает правильно:

for row in select yw, money from pref_money where id=_id order by yw desc limit 20 loop

Надеюсь, это поможет.

0 голосов
/ 28 декабря 2010

Это не совсем JSON, но довольно близко:

SELECT  ARRAY
        (
        SELECT  ROW(yw, money)
        FROM    pref_money
        WHERE   id = 'OK122471020773'
        ORDER BY
                yw DESC
        LIMIT 20
        )::TEXT

Это выведет эту строку:

{"(2010-44:185)","(2010-45:1110)",…,"(2010-52:1130)"}

, которая впоследствии может быть преобразована обратно в соответствующие типы.

...