<?xml version="1.0" encoding="utf-8" ?>

<rss version="2.0" 
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
   xmlns:admin="http://webns.net/mvcb/"
   xmlns:dc="http://purl.org/dc/elements/1.1/"
   xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
   xmlns:wfw="http://wellformedweb.org/CommentAPI/"
   xmlns:content="http://purl.org/rss/1.0/modules/content/"
   >
<channel>
    <title>ads' corner - PL/pgSQL</title>
    <link>http://andreas.scherbaum.la/blog/</link>
    <description>a place to store my stuff</description>
    <dc:language>en</dc:language>
    <generator>Serendipity 1.5.3 - http://www.s9y.org/</generator>
    <pubDate>Wed, 08 Oct 2008 21:35:33 GMT</pubDate>

    <image>
        <url>http://andreas.scherbaum.la/blog/templates/default/img/s9y_banner_small.png</url>
        <title>RSS: ads' corner - PL/pgSQL - a place to store my stuff</title>
        <link>http://andreas.scherbaum.la/blog/</link>
        <width>100</width>
        <height>21</height>
    </image>

<item>
    <title>create language if not exist</title>
    <link>http://andreas.scherbaum.la/blog/archives/346-create-language-if-not-exist.html</link>
            <category>PL/pgSQL</category>
            <category>PostgreSQL</category>
            <category>PostgreSQL News</category>
            <category>SQL</category>
    
    <comments>http://andreas.scherbaum.la/blog/archives/346-create-language-if-not-exist.html#comments</comments>
    <wfw:comment>http://andreas.scherbaum.la/blog/wfwcomment.php?cid=346</wfw:comment>

    <slash:comments>7</slash:comments>
    <wfw:commentRss>http://andreas.scherbaum.la/blog/rss.php?version=2.0&amp;type=comments&amp;cid=346</wfw:commentRss>
    

    <author>nospam@example.com (Andreas 'ads' Scherbaum)</author>
    <content:encoded>
    &lt;div class=&quot;serendipity_authorpic&quot;&gt;&lt;img src=&quot;http://andreas.scherbaum.la/blog/templates/default/img/Andreas__ads__Scherbaum.jpg&quot; alt=&quot;Author&quot; title=&quot;Andreas &#039;ads&#039; Scherbaum&quot; /&gt;&lt;br /&gt;&lt;span&gt;Andreas &#039;ads&#039; Scherbaum&lt;/span&gt;&lt;/div&gt;&lt;p class=&quot;break&quot;&gt;
&lt;font face=&quot;arial,helvetica,sans-serif&quot;&gt;&lt;p&gt;In a customer project i have to setup a database from a Makefile. Part of my problem: on windows the installer may or may not install &amp;quot;plpgsql&amp;quot; into template1 so in consequence this language would be activated in every new database. But that&#039;s not predictable. This problem can appear on different Linux/Unix distributions too.&lt;/p&gt;&lt;p&gt;In contrary to some other opinions in #postgresql i dislike filtering error messages and i prefer clean solutions.&lt;/p&gt;&lt;/font&gt;&lt;/p&gt; &lt;br /&gt;&lt;a href=&quot;http://andreas.scherbaum.la/blog/archives/346-create-language-if-not-exist.html#extended&quot;&gt;Continue reading &quot;create language if not exist&quot;&lt;/a&gt;
    </content:encoded>

    <pubDate>Thu, 27 Mar 2008 08:33:14 +0100</pubDate>
    <guid isPermaLink="false">http://andreas.scherbaum.la/blog/archives/346-guid.html</guid>
    <category>PostgreSQL</category>
<category>SQL</category>
<category>pl/pgSQL</category>

</item>
<item>
    <title>Ringbuffer in SQL</title>
    <link>http://andreas.scherbaum.la/blog/archives/108-Ringbuffer-in-SQL.html</link>
            <category>PL/pgSQL</category>
            <category>PostgreSQL</category>
            <category>PostgreSQL News</category>
    
    <comments>http://andreas.scherbaum.la/blog/archives/108-Ringbuffer-in-SQL.html#comments</comments>
    <wfw:comment>http://andreas.scherbaum.la/blog/wfwcomment.php?cid=108</wfw:comment>

    <slash:comments>3</slash:comments>
    <wfw:commentRss>http://andreas.scherbaum.la/blog/rss.php?version=2.0&amp;type=comments&amp;cid=108</wfw:commentRss>
    

    <author>nospam@example.com (Andreas 'ads' Scherbaum)</author>
    <content:encoded>
    &lt;div class=&quot;serendipity_authorpic&quot;&gt;&lt;img src=&quot;http://andreas.scherbaum.la/blog/templates/default/img/Andreas__ads__Scherbaum.jpg&quot; alt=&quot;Author&quot; title=&quot;Andreas &#039;ads&#039; Scherbaum&quot; /&gt;&lt;br /&gt;&lt;span&gt;Andreas &#039;ads&#039; Scherbaum&lt;/span&gt;&lt;/div&gt;&lt;p class=&quot;break&quot;&gt;
&lt;font face=&quot;arial,helvetica,sans-serif&quot;&gt;On a student platform we show on every page a random user in the upper right corner. Since we have over 11.000 users, the database has to select all matching users and sort them by random(). Thats very expensive and one of the longest running query in the current version.&lt;/font&gt;&lt;p /&gt;&lt;p&gt;&lt;font face=&quot;arial,helvetica,sans-serif&quot;&gt;&lt;/font&gt;&lt;font face=&quot;arial,helvetica,sans-serif&quot;&gt;Since we are currently redeveloping the whole platform, i decided to try something different for the random user. The user must not be really random, it should be enough to just display a different user every time the page is displayed. So my idea was to implement a ringbuffer in SQL and forward the pointer to the next user in the buffer if we need to search the next random user.&lt;/font&gt;&lt;/p&gt;&lt;p /&gt;&lt;p&gt;&lt;br /&gt;First some preparations:&lt;/p&gt;&lt;p /&gt;&lt;/p&gt;&lt;pre&gt;CREATE SCHEMA ringbuffer;&lt;br /&gt;-- create a dummy user table just for this example&lt;br /&gt;CREATE TABLE ringbuffer.users (&lt;br /&gt;  id              INT             NOT NULL&lt;br /&gt;                                  UNIQUE&lt;br /&gt;                                  PRIMARY KEY,&lt;br /&gt;  username        VARCHAR(20)     NOT NULL&lt;br /&gt;                                  UNIQUE&lt;br /&gt;) WITHOUT OIDS;&lt;br /&gt;-- insert some dummy users into our dummy table&lt;br /&gt;INSERT INTO ringbuffer.users (id, username) VALUES (6, &#039;user 6&#039;);&lt;br /&gt;INSERT INTO ringbuffer.users (id, username) VALUES (1, &#039;user 1&#039;);&lt;br /&gt;INSERT INTO ringbuffer.users (id, username) VALUES (2, &#039;user 2&#039;);&lt;br /&gt;INSERT INTO ringbuffer.users (id, username) VALUES (3, &#039;user 3&#039;);&lt;br /&gt;INSERT INTO ringbuffer.users (id, username) VALUES (4, &#039;user 4&#039;);&lt;br /&gt;INSERT INTO ringbuffer.users (id, username) VALUES (5, &#039;user 5&#039;);&lt;/pre&gt;&lt;p&gt;&lt;p /&gt;&lt;p /&gt;&lt;p&gt;&lt;br /&gt;After this, create the ringbuffer:&lt;/p&gt;&lt;p /&gt;&lt;/p&gt;&lt;pre&gt;-- now create the ringbuffer&lt;br /&gt;-- we use a foreign key to the user table to assure we only insert&lt;br /&gt;-- existing userIDs here&lt;br /&gt;CREATE TABLE ringbuffer.ringbuffer (&lt;br /&gt;  id              INT             NOT NULL&lt;br /&gt;                                  UNIQUE&lt;br /&gt;                                  PRIMARY KEY,&lt;br /&gt;  value_id        INT             NOT NULL&lt;br /&gt;                                  REFERENCES ringbuffer.users(id),&lt;br /&gt;  next_id         INT             REFERENCES ringbuffer.ringbuffer(id)&lt;br /&gt;) WITHOUT OIDS;&lt;br /&gt;&lt;br /&gt;-- and an additional status table &lt;br /&gt;CREATE TABLE ringbuffer.ringbuffer_data (&lt;br /&gt;  id              INT             NOT NULL&lt;br /&gt;                                  UNIQUE&lt;br /&gt;                                  PRIMARY KEY&lt;br /&gt;                                  CHECK (id = 1),&lt;br /&gt;  ringbuffer_id   INT             REFERENCES ringbuffer.ringbuffer(id),&lt;br /&gt;  max_id          INT             NOT NULL&lt;br /&gt;                                  DEFAULT 0&lt;br /&gt;) WITHOUT OIDS;&lt;br /&gt;INSERT INTO ringbuffer.ringbuffer_data&lt;br /&gt;            (id, ringbuffer_id, max_id)&lt;br /&gt;     VALUES (1, NULL, 0);&lt;br /&gt;-- protect against deletes, nobody should delete your status entry&lt;br /&gt;-- or the have more overhead in the functions&lt;br /&gt;CREATE RULE ringbuffer_data_del&lt;br /&gt;            AS ON DELETE TO ringbuffer.ringbuffer_data&lt;br /&gt;            DO INSTEAD nothing;&lt;/pre&gt;&lt;p&gt;&lt;p /&gt;&lt;p /&gt;&lt;p&gt;&lt;br /&gt;And some supporting functions:&lt;/p&gt;&lt;p /&gt;&lt;/p&gt;&lt;pre&gt;-- function for insert an user (respective the ID) into the buffer&lt;br /&gt;CREATE OR REPLACE FUNCTION ringbuffer.insert_into_ringbuffer(insert_id INT)&lt;br /&gt;        RETURNS INTEGER&lt;br /&gt;        AS $$&lt;br /&gt;        DECLARE&lt;br /&gt;            query TEXT;&lt;br /&gt;            loop_record RECORD;&lt;br /&gt;            loop_record2 RECORD;&lt;br /&gt;        BEGIN&lt;br /&gt;            -- check that this entry is not yet in the ringbuffer table&lt;br /&gt;            query := &#039;SELECT COUNT(id) AS number_count&lt;br /&gt;                        FROM ringbuffer.ringbuffer&lt;br /&gt;                       WHERE value_id = &#039; || quote_literal(insert_id) || &#039;&#039;;&lt;br /&gt;            EXECUTE query INTO loop_record;&lt;br /&gt;            IF loop_record.number_count &amp;gt; 0&lt;br /&gt;            THEN&lt;br /&gt;                RAISE NOTICE &#039;user is already in ringbuffer: %&#039;, insert_id;&lt;br /&gt;            ELSE&lt;br /&gt;                -- now check, if the data table is empty&lt;br /&gt;                query := &#039;SELECT *&lt;br /&gt;                            FROM ringbuffer.ringbuffer_data&lt;br /&gt;                           WHERE id = 1&#039;;&lt;br /&gt;                EXECUTE query INTO loop_record;&lt;br /&gt;                RAISE NOTICE &#039;max id: %&#039;, loop_record.max_id;&lt;br /&gt;                IF loop_record.max_id &amp;gt; 0&lt;br /&gt;                THEN&lt;br /&gt;                    -- need the current last record&lt;br /&gt;                    query := &#039;SELECT *&lt;br /&gt;                                FROM ringbuffer.ringbuffer&lt;br /&gt;                               WHERE id = &#039; || quote_literal(loop_record.max_id) || &#039;&#039;;&lt;br /&gt;                    EXECUTE query INTO loop_record2;&lt;br /&gt;                    IF loop_record2.next_id &amp;lt; 1&lt;br /&gt;                    THEN&lt;br /&gt;                        RAISE EXCEPTION &#039;should have a next_id, but missing it&#039;;&lt;br /&gt;                    END IF;&lt;br /&gt;                    -- insert new record at end of table&lt;br /&gt;                    RAISE NOTICE &#039;insert at end of table with id: %&#039;, loop_record.max_id + 1;&lt;br /&gt;                    query := &#039;INSERT INTO ringbuffer.ringbuffer&lt;br /&gt;                                          (id, value_id, next_id)&lt;br /&gt;                                   VALUES (&#039; || quote_literal(loop_record.max_id + 1) || &#039;,&lt;br /&gt;                                           &#039; || quote_literal(insert_id) || &#039;,&lt;br /&gt;                                           &#039; || quote_literal(loop_record2.next_id) || &#039;)&#039;;&lt;br /&gt;                    -- RAISE NOTICE &#039;query: %&#039;, query;&lt;br /&gt;                    EXECUTE query;&lt;br /&gt;                    -- update last record&lt;br /&gt;                    query := &#039;UPDATE ringbuffer.ringbuffer&lt;br /&gt;                                 SET next_id=&#039; || quote_literal(loop_record.max_id + 1) || &#039;&lt;br /&gt;                               WHERE id=&#039; || quote_literal(loop_record.max_id) || &#039;&#039;;&lt;br /&gt;                    -- RAISE NOTICE &#039;query: %&#039;, query;&lt;br /&gt;                    EXECUTE query;&lt;br /&gt;                    -- update pointer table&lt;br /&gt;                    query := &#039;UPDATE ringbuffer.ringbuffer_data&lt;br /&gt;                                 SET max_id = &#039; || quote_literal(loop_record.max_id + 1) || &#039;&lt;br /&gt;                               WHERE id = 1&#039;;&lt;br /&gt;                    -- RAISE NOTICE &#039;query: %&#039;, query;&lt;br /&gt;                    EXECUTE query;&lt;br /&gt;                ELSE&lt;br /&gt;                    -- just insert as first value&lt;br /&gt;                    RAISE NOTICE &#039;insert as first value into ringbuffer ...&#039;;&lt;br /&gt;                    query := &#039;INSERT INTO ringbuffer.ringbuffer&lt;br /&gt;                                          (id, value_id, next_id)&lt;br /&gt;                                   VALUES (1, &#039; || quote_literal(insert_id) || &#039;, 1)&#039;;&lt;br /&gt;                    -- RAISE NOTICE &#039;query: %&#039;, query;&lt;br /&gt;                    EXECUTE query;&lt;br /&gt;                    -- update pointer table&lt;br /&gt;                    query := &#039;UPDATE ringbuffer.ringbuffer_data&lt;br /&gt;                                 SET max_id = &#039; || quote_literal(loop_record.max_id + 1) || &#039;,&lt;br /&gt;                                     ringbuffer_id = 1&lt;br /&gt;                               WHERE id = 1&#039;;&lt;br /&gt;                    -- RAISE NOTICE &#039;query: %&#039;, query;&lt;br /&gt;                    EXECUTE query;&lt;br /&gt;                END IF;&lt;br /&gt;            END IF;&lt;br /&gt;&lt;br /&gt;            RETURN 1;&lt;br /&gt;        END;&lt;br /&gt;        $$&lt;br /&gt;        LANGUAGE &#039;plpgsql&#039;;&lt;br /&gt;&lt;br /&gt;-- function for get next user from rungbuffer (the semi-random function)&lt;br /&gt;CREATE OR REPLACE FUNCTION ringbuffer.get_next_ringbuffer()&lt;br /&gt;        RETURNS INTEGER&lt;br /&gt;        AS $$&lt;br /&gt;        DECLARE&lt;br /&gt;            query TEXT;&lt;br /&gt;            loop_record RECORD;&lt;br /&gt;        BEGIN&lt;br /&gt;            -- check, if the table is empty&lt;br /&gt;            query :=&#039;SELECT *&lt;br /&gt;                       FROM ringbuffer.ringbuffer_data&lt;br /&gt;                      WHERE id = 1&#039;;&lt;br /&gt;            EXECUTE query INTO loop_record;&lt;br /&gt;            -- RAISE NOTICE &#039;max id: %&#039;, loop_record.max_id;&lt;br /&gt;            IF loop_record.max_id IS NULL&lt;br /&gt;            THEN&lt;br /&gt;                RAISE NOTICE &#039;ringbuffer is empty!&#039;;&lt;br /&gt;                RETURN NULL;&lt;br /&gt;            ELSE&lt;br /&gt;                -- get the value the pointer is currently on&lt;br /&gt;                RAISE NOTICE &#039;get value from ringbuffer ...&#039;;&lt;br /&gt;                query := &#039;SELECT *&lt;br /&gt;                            FROM ringbuffer.ringbuffer&lt;br /&gt;                           WHERE id = (SELECT ringbuffer_id&lt;br /&gt;                                         FROM ringbuffer.ringbuffer_data&lt;br /&gt;                                        WHERE id = 1)&#039;;&lt;br /&gt;                -- RAISE NOTICE &#039;query: %&#039;, query;&lt;br /&gt;                EXECUTE query INTO loop_record;&lt;br /&gt;                RAISE NOTICE &#039;current value id: %&#039;, loop_record.value_id;&lt;br /&gt;                RAISE NOTICE &#039;next id: %&#039;, loop_record.next_id;&lt;br /&gt;                -- update pointer table&lt;br /&gt;                query := &#039;UPDATE ringbuffer.ringbuffer_data&lt;br /&gt;                             SET ringbuffer_id=&#039; || quote_literal(loop_record.next_id) || &#039;&lt;br /&gt;                           WHERE id = 1&#039;;&lt;br /&gt;                -- RAISE NOTICE &#039;query: %&#039;, query;&lt;br /&gt;                EXECUTE query;&lt;br /&gt;                -- return result&lt;br /&gt;                RETURN loop_record.value_id;&lt;br /&gt;            END IF;&lt;br /&gt;&lt;br /&gt;            RETURN NULL;&lt;br /&gt;        END;&lt;br /&gt;        $$&lt;br /&gt;        LANGUAGE &#039;plpgsql&#039;;&lt;br /&gt;&lt;br /&gt;-- function for delete an user from ringbuffer&lt;br /&gt;CREATE OR REPLACE FUNCTION ringbuffer.delete_from_ringbuffer(delete_id INT)&lt;br /&gt;        RETURNS INTEGER&lt;br /&gt;        AS $$&lt;br /&gt;        DECLARE&lt;br /&gt;            query TEXT;&lt;br /&gt;            loop_record_data RECORD;&lt;br /&gt;            loop_record RECORD;&lt;br /&gt;            loop_record2 RECORD;&lt;br /&gt;        BEGIN&lt;br /&gt;            -- check, if the table is empty&lt;br /&gt;            query :=&#039;SELECT *&lt;br /&gt;                       FROM ringbuffer.ringbuffer_data&lt;br /&gt;                      WHERE id = 1&#039;;&lt;br /&gt;            EXECUTE query INTO loop_record_data;&lt;br /&gt;            -- RAISE NOTICE &#039;max id: %&#039;, loop_record.max_id;&lt;br /&gt;            IF loop_record_data.max_id IS NULL&lt;br /&gt;            THEN&lt;br /&gt;                RAISE NOTICE &#039;ringbuffer is empty!&#039;;&lt;br /&gt;                RETURN NULL;&lt;br /&gt;            ELSE&lt;br /&gt;                -- get the value which should be deleted&lt;br /&gt;                -- RAISE NOTICE &#039;delete value from ringbuffer ...&#039;;&lt;br /&gt;                query := &#039;SELECT *&lt;br /&gt;                            FROM ringbuffer.ringbuffer&lt;br /&gt;                           WHERE value_id = &#039; || quote_literal(delete_id) || &#039;&#039;;&lt;br /&gt;                -- RAISE NOTICE &#039;query: %&#039;, query;&lt;br /&gt;                EXECUTE query INTO loop_record;&lt;br /&gt;                IF loop_record.id IS NULL&lt;br /&gt;                THEN&lt;br /&gt;                    -- nothing to delete&lt;br /&gt;                    RETURN NULL;&lt;br /&gt;                END IF;&lt;br /&gt;                IF loop_record.id = loop_record.next_id&lt;br /&gt;                THEN&lt;br /&gt;                    -- we only have this value, update pointer table&lt;br /&gt;                    -- (next_id == id)&lt;br /&gt;                    query := &#039;UPDATE ringbuffer.ringbuffer_data&lt;br /&gt;                                 SET ringbuffer_id = NULL,&lt;br /&gt;                                     max_id = 0&lt;br /&gt;                               WHERE id = 1&#039;;&lt;br /&gt;                    -- RAISE NOTICE &#039;query: %&#039;, query;&lt;br /&gt;                    EXECUTE query;&lt;br /&gt;                ELSE&lt;br /&gt;                    -- get the value which is referring us&lt;br /&gt;                    query := &#039;SELECT *&lt;br /&gt;                                FROM ringbuffer.ringbuffer&lt;br /&gt;                               WHERE next_id = &#039; || quote_literal(loop_record.id) || &#039;&#039;;&lt;br /&gt;                    -- RAISE NOTICE &#039;query: %&#039;, query;&lt;br /&gt;                    EXECUTE query INTO loop_record2;&lt;br /&gt;                    -- now twist the pointer from last to the next record&lt;br /&gt;                    query := &#039;UPDATE ringbuffer.ringbuffer&lt;br /&gt;                                 SET next_id = &#039; || quote_literal(loop_record.next_id) || &#039;&lt;br /&gt;                               WHERE id= &#039; || quote_literal(loop_record2.id) || &#039;&#039;;&lt;br /&gt;                    -- RAISE NOTICE &#039;query: %&#039;, query;&lt;br /&gt;                    EXECUTE query;&lt;br /&gt;                    IF loop_record_data.ringbuffer_id = loop_record.id&lt;br /&gt;                    THEN&lt;br /&gt;                        -- we are deleting the next entry&lt;br /&gt;                        query := &#039;UPDATE ringbuffer.ringbuffer_data&lt;br /&gt;                                     SET ringbuffer_id = &#039; || quote_literal(loop_record.next_id) || &#039;,&lt;br /&gt;                                         max_id = (SELECT MAX(next_id)&lt;br /&gt;                                                     FROM ringbuffer.ringbuffer)&lt;br /&gt;                                   WHERE id = 1&#039;;&lt;br /&gt;                        -- RAISE NOTICE &#039;query: %&#039;, query;&lt;br /&gt;                        EXECUTE query;&lt;br /&gt;                    ELSE&lt;br /&gt;                        -- we are deleting another entry&lt;br /&gt;                        query := &#039;UPDATE ringbuffer.ringbuffer_data&lt;br /&gt;                                     SET max_id = (SELECT MAX(next_id)&lt;br /&gt;                                                     FROM ringbuffer.ringbuffer)&lt;br /&gt;                                   WHERE id = 1&#039;;&lt;br /&gt;                        -- RAISE NOTICE &#039;query: %&#039;, query;&lt;br /&gt;                        EXECUTE query;&lt;br /&gt;                    END IF;&lt;br /&gt;&lt;br /&gt;                END IF;&lt;br /&gt;                -- delete the dataset&lt;br /&gt;                query := &#039;DELETE FROM ringbuffer.ringbuffer&lt;br /&gt;                           WHERE id = &#039; || quote_literal(loop_record.id) || &#039;&#039;;&lt;br /&gt;                -- RAISE NOTICE &#039;query: %&#039;, query;&lt;br /&gt;                EXECUTE query;&lt;br /&gt;                -- return deleted result&lt;br /&gt;                RETURN loop_record.value_id;&lt;br /&gt;            END IF;&lt;br /&gt;&lt;br /&gt;            RETURN NULL;&lt;br /&gt;        END;&lt;br /&gt;        $$&lt;br /&gt;        LANGUAGE &#039;plpgsql&#039;;&lt;/pre&gt;&lt;p&gt;&lt;p /&gt;&lt;p /&gt;&lt;p&gt;&lt;br /&gt;Now lets test this stuff:&lt;/p&gt;&lt;p /&gt;&lt;/p&gt;&lt;pre&gt;SELECT ringbuffer.insert_into_ringbuffer((SELECT id&lt;br /&gt;                                            FROM ringbuffer.users&lt;br /&gt;                                           WHERE username=&#039;user 1&#039;));&lt;br /&gt;SELECT ringbuffer.insert_into_ringbuffer((SELECT id&lt;br /&gt;                                            FROM ringbuffer.users&lt;br /&gt;                                           WHERE username=&#039;user 2&#039;));&lt;br /&gt;SELECT ringbuffer.insert_into_ringbuffer((SELECT id&lt;br /&gt;                                            FROM ringbuffer.users&lt;br /&gt;                                           WHERE username=&#039;user 5&#039;));&lt;br /&gt;SELECT ringbuffer.insert_into_ringbuffer((SELECT id&lt;br /&gt;                                            FROM ringbuffer.users&lt;br /&gt;                                           WHERE username=&#039;user 4&#039;));&lt;br /&gt;SELECT ringbuffer.insert_into_ringbuffer((SELECT id&lt;br /&gt;                                            FROM ringbuffer.users&lt;br /&gt;                                           WHERE username=&#039;user 3&#039;));&lt;br /&gt;SELECT ringbuffer.insert_into_ringbuffer((SELECT id&lt;br /&gt;                                            FROM ringbuffer.users&lt;br /&gt;                                           WHERE username=&#039;user 6&#039;));&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SELECT * FROM ringbuffer.ringbuffer ORDER BY id;&lt;br /&gt;SELECT * FROM ringbuffer.ringbuffer_data ORDER BY id;&lt;br /&gt;SELECT ringbuffer.get_next_ringbuffer();&lt;br /&gt;SELECT ringbuffer.get_next_ringbuffer();&lt;br /&gt;SELECT ringbuffer.get_next_ringbuffer();&lt;br /&gt;SELECT ringbuffer.get_next_ringbuffer();&lt;br /&gt;SELECT ringbuffer.get_next_ringbuffer();&lt;br /&gt;SELECT ringbuffer.get_next_ringbuffer();&lt;/pre&gt;&lt;p&gt;&lt;p /&gt;&lt;p&gt;&lt;br /&gt;As you can see, every time you call ringbuffer.get_next_ringbuffer(), you get another userID back, which will perfectly fit in a subselect to retrieve the actual userdata.&lt;/p&gt;&lt;p&gt;&lt;font face=&quot;arial,helvetica,sans-serif&quot;&gt;&lt;/font&gt;&lt;/p&gt;&lt;/p&gt; 
    </content:encoded>

    <pubDate>Sun, 04 Feb 2007 21:50:30 +0100</pubDate>
    <guid isPermaLink="false">http://andreas.scherbaum.la/blog/archives/108-guid.html</guid>
    <category>PostgreSQL</category>
<category>pl/pgSQL</category>

</item>

</channel>
</rss>
