I have a journal system that has a table structure like:
[journal_logs]
id
title
created_at
[journal_entries]
id
journal_log_id
body
created_at
So a "journal_log" is made up of one or more "entries".
On my webpage I want to list the most recent logs, along with the entries.
Example:
"Log 10"
"entry 1"
"entry 2"
"entry 3"
"Log 9"
"entry 1"
"Log 8"
"entry 1"
"entry 2"
Is it possible to produce an output like this with a single query?
here is example with <UL><LI>
data sample:
t=# create table journal_logs(id int,title text);
CREATE TABLE
t=# create table journal_entries(id int,journal_log_id int);
CREATE TABLE
t=# insert into journal_logs select 8,'a';
INSERT 0 1
t=# insert into journal_logs select 9,'a';
INSERT 0 1
t=# insert into journal_logs select 10,'a';
INSERT 0 1
t=# insert into journal_entries select 1,8;
INSERT 0 1
t=# insert into journal_entries select 2,8;
INSERT 0 1
t=# insert into journal_entries select 1,9;
INSERT 0 1
t=# insert into journal_entries select 1,10;
INSERT 0 1
t=# insert into journal_entries select 2,10;
INSERT 0 1
t=# insert into journal_entries select 3,10;
INSERT 0 1
query sample:
t=# with p as (
select concat('<ul>',l.id,l.title) ul,concat('<li>',e.id) li
from journal_logs l
join journal_entries e on l.id = journal_log_id
)
select
concat(
case when li = min(li) over (partition by ul order by li) then ul end
,concat(li, case when li = max(li) over (partition by ul) then '</ul>' end)) html
from p;
html
------------------
<ul>10a<li>1
<li>2
<li>3</ul>
<ul>8a<li>1
<li>2</ul>
<ul>9a<li>1</ul>
(6 rows)
<ul>10a<li>1
<li>2
<li>3</ul>
<ul>8a<li>1
<li>2</ul>
<ul>9a<li>1</ul>
Related
I have a table that regroups some users and which event (as in IRL event) they've joined.
I have set up a server query that lets a user join an event.
It goes like this :
INSERT INTO participations
VALUES(:usr,:event_id)
I want that statement to also return the number of people who have joined the same event as the user. How do I proceed? If possible in one SQL statement.
Thanks
You can use a common table expression like this to execute it as one query.
with insert_tbl_statement as (
insert into tbl values (4, 1) returning event_id
)
select (count(*) + 1) as event_count from tbl where event_id = (select event_id from insert_tbl_statement);
see demo http://rextester.com/BUF16406
You can use a function, I've set up next example, but keep in mind you must add 1 to the final count because still transaction hasn't been committed.
create table tbl(id int, event_id int);
✓
insert into tbl values (1, 2),(2, 2),(3, 3);
3 rows affected
create function new_tbl(id int, event_id int)
returns bigint as $$
insert into tbl values ($1, $2);
select count(*) + 1 from tbl where event_id = $2;
$$ language sql;
✓
select new_tbl(4, 2);
| new_tbl |
| ------: |
| 4 |
db<>fiddle here
Assuming I have a parent table with child partitions that are created based on the value of a field.
If the value of that field changes, is there a way to have Postgres automatically move the row into the appropriate partition?
For example:
create table my_table(name text)
partition by list (left(name, 1));
create table my_table_a
partition of my_table
for values in ('a');
create table my_table_b
partition of my_table
for values in ('b');
In this case, if I change the value of name in a row from aaa to bbb, how can I get it to automatically move that row into my_table_b.
When I tried to do that, (i.e. update my_table set name = 'bbb' where name = 'aaa';), I get the following error:
ERROR: new row for relation "my_table_a" violates partition constraint
https://git.postgresql.org/gitweb/?p=postgresql.git;a=commitdiff;h=f0e44751d7175fa3394da2c8f85e3ceb3cdbfe63
it doesn't handle updates that cross partition boundaries.
thus you need to create one yourself... here's your set:
t=# insert into my_table select 'abc';
INSERT 0 1
t=# insert into my_table select 'bcd';
INSERT 0 1
t=# select tableoid::regclass,* from my_table;
tableoid | name
------------+------
my_table_a | abc
my_table_b | bcd
(2 rows)
here's rule and fn():
t=# create or replace function puf(_j json,_o text) returns void as $$
begin
raise info '%',': '||left(_j->>'name',1);
execute format('insert into %I select * from json_populate_record(null::my_table, %L)','my_table_'||left(_j->>'name',1), _j);
execute format('delete from %I where name = %L','my_table_'||left(_o,1), _o);
end;
$$language plpgsql;
CREATE FUNCTION
t=# create rule psr AS ON update to my_table do instead select puf(row_to_json(n),OLD.name) from (select NEW.*) n;
CREATE RULE
here's update:
t=# update my_table set name = 'bbb' where name = 'abc';
INFO: : b
puf
-----
(1 row)
UPDATE 0
checking result:
t=# select tableoid::regclass,* from my_table;
tableoid | name
------------+------
my_table_b | bcd
my_table_b | bbb
(2 rows)
once again:
t=# update my_table set name = 'a1' where name = 'bcd';
INFO: : a
puf
-----
(1 row)
UPDATE 0
t=# select tableoid::regclass,* from my_table;
tableoid | name
------------+------
my_table_a | a1
my_table_b | bbb
(2 rows)
Of course using json to pass NEW record looks ugly. And it is ugly indeed. But I did not have time to study the new PARTITION feature of 10, so don't know the elegant way to do this task. Hopefully I could give the generic idea of how you can possible solve the problem and you will produce a better neat code.
update
its probablygood idea to limit such rule to ON update to my_table where left(NEW.name,1) <> left(OLD.name,1) do instead, to release the heavy manipulations need
Generate gen_random_uuid() for the column key if there count(key) < 1
My table name is keytable and column is key.
I am using the below insert statement to generate the uuid : that is the only value in the table.
INSERT INTO keytable VALUES(gen_random_uuid());
key
---------------------------------------
5686473e-add1-4ab1-be85-7e62152ce539
I wanted to run this insert statement only when i dont have any values in my "key" column.
in other words, if count(key) < 1 then i want to run the INSERT INTO keytable VALUES(gen_random_uuid());
Please help.
use INSERT ... SELECT construct instead
t=# begin; insert into keytable select gen_random_uuid() where (select count(key) from keytable) < 1;
BEGIN
INSERT 0 1
t=# insert into keytable select gen_random_uuid() where (select count(key) from keytable) < 1;
INSERT 0 0
t=# rollback;
ROLLBACK
Already Answered By Clodoaldo Neto (Link Below)
here is according to your perspective
insert into keytable
select gen_random_uuid()
where not exists ( select key from keytable );
It will only insert the result of select statement when
select key from keytable
this does not return anything!
for more info: https://stackoverflow.com/a/15710598/8506841
I want to insert data from one table ("tmp") into another ("tbla"), using the on conflict do update-feature.
My Code:
INSERT INTO tbla (id, col1, col2, col3)
SELECT id, col1, col2, col3 FROM tmp
ON CONFLICT on constraint pkey_tbla DO UPDATE SET col1=tmp.col1 FROM tmp;
DROP TABLE tmp;
This code gives me back an Syntax-Error at "FROM tmp;"
Without FROM there is the ERROR: missing FROM-clause entry for table "tmp"
Any suggestions on what I'm doing wrong?
DB-Server is running on localhost at a windows 7-machine with postgres 9.5
Documentation "Note that the special excluded table is used to reference values originally proposed for insertion" https://www.postgresql.org/docs/9.5/static/sql-insert.html
Fix : ... DO UPDATE SET col1=EXCLUDED.col1;
x=> select * from tbla;
id | col1
----+------
1 | 2
2 | 3
(2 rows)
x=> truncate tmp;
TRUNCATE TABLE
x=> insert into tmp(id,col1) values (1,42);
INSERT 0 1
x=> INSERT INTO tbla(id,col1) SELECT id,col1 FROM tmp -- wrap line
ON CONFLICT (id) DO UPDATE SET col1=EXCLUDED.col1;
INSERT 0 1
sh161119=> select * from tbla;
id | col1
----+------
2 | 3
1 | 42
(2 rows)
I have following table structure
table 1
ID SOURCE_ID NAME
1 1 A
2 1 B
3 2 B
4 2 C
5 2 A
i need to pick those names which are common across all SOURCE_ID , hence i expect names A and B as they are present in both the SOURCE_ID 1,2.
The following query gives me the expected output:
SELECT DISTINCT NAME
FROM TABLE1 A, TABLE1 B
WHERE A.NAME = B.NAME AND A.SOURCE_ID != B.SOURCE_ID
Now when the data in table changes to include a new record ID 6
table 1
ID SOURCE_ID NAME
1 1 A
2 1 B
3 2 B
4 2 C
5 2 A
6 3 A
The name that is common in all three SOURCE_ID(1,2,3) IS A.
My query fails to return the correct output as new records are entered.
Please provide me a query that works correctly when new records are inserted.
Have a look at something like
DECLARE #Table TABLE(
SOURCE_ID INT,
NAME VARCHAR(20)
)
INSERT INTO #Table SELECT 1,'A'
INSERT INTO #Table SELECT 1,'B'
INSERT INTO #Table SELECT 2,'B'
INSERT INTO #Table SELECT 2,'C'
INSERT INTO #Table SELECT 2,'A'
--INSERT INTO #Table SELECT 3,'A'
;WITH DistinctCount AS (
SELECT NAME,
COUNT(DISTINCT SOURCE_ID) Cnt
FROM #Table
GROUP BY NAME
)
SELECT *
FROM DistinctCount
WHERE Cnt = (SELECT COUNT(DISTINCT SOURCE_ID) FROM #Table)
With the 6th insert commented out, should return A and B, with it included, should return A