Join three rows if the same value in one column
There is a Postgres database and the table has three columns. The data structure is in external system so I can not modify it.
Every object is represented by three rows (identified by column element_id - rows with the same value in this column represents the same object), for example:
key value element_id
-----------------------------------
status active 1
name exampleNameAAA 1
city exampleCityAAA 1
status inactive 2
name exampleNameBBB 2
city exampleCityBBB 2
status inactive 3
name exampleNameCCC 3
city exampleCityCCC 3
I want to get all values describing every objects (name, status and city).
For this example the output should be like:
exampleNameAAA | active | exampleCityAAA
exampleNameBBB | inactive | exampleCityBBB
exampleNameCCC | inactive | exampleCityCCC
I know how to join two rows:
select a.value as name,
b.value as status
from the_table a
join the_table b
on a.element_id = b.element_id
and b."key" = 'status'
where a."key" = 'name';
How is it possible to join three columns?
sql database postgresql
add a comment |
There is a Postgres database and the table has three columns. The data structure is in external system so I can not modify it.
Every object is represented by three rows (identified by column element_id - rows with the same value in this column represents the same object), for example:
key value element_id
-----------------------------------
status active 1
name exampleNameAAA 1
city exampleCityAAA 1
status inactive 2
name exampleNameBBB 2
city exampleCityBBB 2
status inactive 3
name exampleNameCCC 3
city exampleCityCCC 3
I want to get all values describing every objects (name, status and city).
For this example the output should be like:
exampleNameAAA | active | exampleCityAAA
exampleNameBBB | inactive | exampleCityBBB
exampleNameCCC | inactive | exampleCityCCC
I know how to join two rows:
select a.value as name,
b.value as status
from the_table a
join the_table b
on a.element_id = b.element_id
and b."key" = 'status'
where a."key" = 'name';
How is it possible to join three columns?
sql database postgresql
1
Simply add another JOIN. Keep the one and only WHERE at the end.
– jarlh
Nov 23 '18 at 10:06
@jarlh could you post the example?
– john bernat
Nov 23 '18 at 10:07
SELECT t1.c1, t2.cx ... FROM t1 JOIN t2 ON ... JOIN t3 ON ... WHERE...
– jarlh
Nov 23 '18 at 10:09
add a comment |
There is a Postgres database and the table has three columns. The data structure is in external system so I can not modify it.
Every object is represented by three rows (identified by column element_id - rows with the same value in this column represents the same object), for example:
key value element_id
-----------------------------------
status active 1
name exampleNameAAA 1
city exampleCityAAA 1
status inactive 2
name exampleNameBBB 2
city exampleCityBBB 2
status inactive 3
name exampleNameCCC 3
city exampleCityCCC 3
I want to get all values describing every objects (name, status and city).
For this example the output should be like:
exampleNameAAA | active | exampleCityAAA
exampleNameBBB | inactive | exampleCityBBB
exampleNameCCC | inactive | exampleCityCCC
I know how to join two rows:
select a.value as name,
b.value as status
from the_table a
join the_table b
on a.element_id = b.element_id
and b."key" = 'status'
where a."key" = 'name';
How is it possible to join three columns?
sql database postgresql
There is a Postgres database and the table has three columns. The data structure is in external system so I can not modify it.
Every object is represented by three rows (identified by column element_id - rows with the same value in this column represents the same object), for example:
key value element_id
-----------------------------------
status active 1
name exampleNameAAA 1
city exampleCityAAA 1
status inactive 2
name exampleNameBBB 2
city exampleCityBBB 2
status inactive 3
name exampleNameCCC 3
city exampleCityCCC 3
I want to get all values describing every objects (name, status and city).
For this example the output should be like:
exampleNameAAA | active | exampleCityAAA
exampleNameBBB | inactive | exampleCityBBB
exampleNameCCC | inactive | exampleCityCCC
I know how to join two rows:
select a.value as name,
b.value as status
from the_table a
join the_table b
on a.element_id = b.element_id
and b."key" = 'status'
where a."key" = 'name';
How is it possible to join three columns?
sql database postgresql
sql database postgresql
edited Nov 23 '18 at 10:01
Mayank Porwal
4,9202724
4,9202724
asked Nov 23 '18 at 9:59
john bernatjohn bernat
174
174
1
Simply add another JOIN. Keep the one and only WHERE at the end.
– jarlh
Nov 23 '18 at 10:06
@jarlh could you post the example?
– john bernat
Nov 23 '18 at 10:07
SELECT t1.c1, t2.cx ... FROM t1 JOIN t2 ON ... JOIN t3 ON ... WHERE...
– jarlh
Nov 23 '18 at 10:09
add a comment |
1
Simply add another JOIN. Keep the one and only WHERE at the end.
– jarlh
Nov 23 '18 at 10:06
@jarlh could you post the example?
– john bernat
Nov 23 '18 at 10:07
SELECT t1.c1, t2.cx ... FROM t1 JOIN t2 ON ... JOIN t3 ON ... WHERE...
– jarlh
Nov 23 '18 at 10:09
1
1
Simply add another JOIN. Keep the one and only WHERE at the end.
– jarlh
Nov 23 '18 at 10:06
Simply add another JOIN. Keep the one and only WHERE at the end.
– jarlh
Nov 23 '18 at 10:06
@jarlh could you post the example?
– john bernat
Nov 23 '18 at 10:07
@jarlh could you post the example?
– john bernat
Nov 23 '18 at 10:07
SELECT t1.c1, t2.cx ... FROM t1 JOIN t2 ON ... JOIN t3 ON ... WHERE...
– jarlh
Nov 23 '18 at 10:09
SELECT t1.c1, t2.cx ... FROM t1 JOIN t2 ON ... JOIN t3 ON ... WHERE...
– jarlh
Nov 23 '18 at 10:09
add a comment |
3 Answers
3
active
oldest
votes
You can try below
DEMO
select a.value as name,
b.value as status,c.value as city
from t1 a
join t1 b
on a.element_id = b.element_id and b."keys" = 'status'
join t1 c on a.element_id = c.element_id and c."keys" = 'city'
where a."keys" = 'name';
OUTPUT
name status city
exampleNameAAA active exampleCityAAA
exampleNameBBB inactive exampleCityBBB
exampleNameCCC inactive exampleCityCCC
add a comment |
One option is to simply add another join for each value you need (this is one of the big disadvantages of the EAV (anti) pattern you are using:
select a.value as name,
b.value as status,
c.value as city
from the_table a
join the_table b on a.element_id = b.element_id and b."key" = 'status'
join the_table c on a.element_id = c.element_id and c."key" = 'city'
where a."key" = 'name';
Another option is to aggregate all key/value pairs for an element into a JSON then you can easily access each one without additional joins:
select t.element_id,
t.obj ->> 'city' as city,
t.obj ->> 'status' as status,
t.obj ->> 'name' as name
from (
select e.element_id, jsonb_object_agg("key", value) as obj
from element e
group by e.element_id
) t;
If the table is really big this might be a lot slower than the join version due to the aggregation step. If you limit the query to only some elements (e.g. by adding a where element_id = 1
or where element_id in (1,2,3)
) then this should be quite fast.
It has the advantage that you always have all key/value pairs for each element_id available regardless on what you do. The inner select could be put into a view, to make things easier.
Online example: https://rextester.com/MSZOWU37182
add a comment |
Seems like you want to PIVOT
One way to do that is via conditional aggregation.
select
-- t.element_id,
max(case when t.key = 'name' then t.value end) as name,
max(case when t.key = 'status' then t.value end) as status,
max(case when t.key = 'city' then t.value end) as city
from the_table t
group by t.element_id;
db<>fiddle here
Or use crosstab:
select
-- element_id,
name,
status,
city
from crosstab (
'select t.element_id, t.key, t.value
from the_table t'
) as ct (element_id int, name varchar(30), status varchar(30), city varchar(30));
But if you do like those joins, here's a way
select
-- el.element_id,
nm.value as name,
st.value as status,
ci.value as city
from
(
select distinct t.element_id
from the_table t
where t.key in ('name','status','city')
) as el
left join the_table as nm on (nm.element_id = el.element_id and nm.key = 'name')
left join the_table as st on (st.element_id = el.element_id and st.key = 'status')
left join the_table as ci on (ci.element_id = el.element_id and ci.key = 'city');
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53444419%2fjoin-three-rows-if-the-same-value-in-one-column%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
You can try below
DEMO
select a.value as name,
b.value as status,c.value as city
from t1 a
join t1 b
on a.element_id = b.element_id and b."keys" = 'status'
join t1 c on a.element_id = c.element_id and c."keys" = 'city'
where a."keys" = 'name';
OUTPUT
name status city
exampleNameAAA active exampleCityAAA
exampleNameBBB inactive exampleCityBBB
exampleNameCCC inactive exampleCityCCC
add a comment |
You can try below
DEMO
select a.value as name,
b.value as status,c.value as city
from t1 a
join t1 b
on a.element_id = b.element_id and b."keys" = 'status'
join t1 c on a.element_id = c.element_id and c."keys" = 'city'
where a."keys" = 'name';
OUTPUT
name status city
exampleNameAAA active exampleCityAAA
exampleNameBBB inactive exampleCityBBB
exampleNameCCC inactive exampleCityCCC
add a comment |
You can try below
DEMO
select a.value as name,
b.value as status,c.value as city
from t1 a
join t1 b
on a.element_id = b.element_id and b."keys" = 'status'
join t1 c on a.element_id = c.element_id and c."keys" = 'city'
where a."keys" = 'name';
OUTPUT
name status city
exampleNameAAA active exampleCityAAA
exampleNameBBB inactive exampleCityBBB
exampleNameCCC inactive exampleCityCCC
You can try below
DEMO
select a.value as name,
b.value as status,c.value as city
from t1 a
join t1 b
on a.element_id = b.element_id and b."keys" = 'status'
join t1 c on a.element_id = c.element_id and c."keys" = 'city'
where a."keys" = 'name';
OUTPUT
name status city
exampleNameAAA active exampleCityAAA
exampleNameBBB inactive exampleCityBBB
exampleNameCCC inactive exampleCityCCC
answered Nov 23 '18 at 10:22
fa06fa06
13.4k2917
13.4k2917
add a comment |
add a comment |
One option is to simply add another join for each value you need (this is one of the big disadvantages of the EAV (anti) pattern you are using:
select a.value as name,
b.value as status,
c.value as city
from the_table a
join the_table b on a.element_id = b.element_id and b."key" = 'status'
join the_table c on a.element_id = c.element_id and c."key" = 'city'
where a."key" = 'name';
Another option is to aggregate all key/value pairs for an element into a JSON then you can easily access each one without additional joins:
select t.element_id,
t.obj ->> 'city' as city,
t.obj ->> 'status' as status,
t.obj ->> 'name' as name
from (
select e.element_id, jsonb_object_agg("key", value) as obj
from element e
group by e.element_id
) t;
If the table is really big this might be a lot slower than the join version due to the aggregation step. If you limit the query to only some elements (e.g. by adding a where element_id = 1
or where element_id in (1,2,3)
) then this should be quite fast.
It has the advantage that you always have all key/value pairs for each element_id available regardless on what you do. The inner select could be put into a view, to make things easier.
Online example: https://rextester.com/MSZOWU37182
add a comment |
One option is to simply add another join for each value you need (this is one of the big disadvantages of the EAV (anti) pattern you are using:
select a.value as name,
b.value as status,
c.value as city
from the_table a
join the_table b on a.element_id = b.element_id and b."key" = 'status'
join the_table c on a.element_id = c.element_id and c."key" = 'city'
where a."key" = 'name';
Another option is to aggregate all key/value pairs for an element into a JSON then you can easily access each one without additional joins:
select t.element_id,
t.obj ->> 'city' as city,
t.obj ->> 'status' as status,
t.obj ->> 'name' as name
from (
select e.element_id, jsonb_object_agg("key", value) as obj
from element e
group by e.element_id
) t;
If the table is really big this might be a lot slower than the join version due to the aggregation step. If you limit the query to only some elements (e.g. by adding a where element_id = 1
or where element_id in (1,2,3)
) then this should be quite fast.
It has the advantage that you always have all key/value pairs for each element_id available regardless on what you do. The inner select could be put into a view, to make things easier.
Online example: https://rextester.com/MSZOWU37182
add a comment |
One option is to simply add another join for each value you need (this is one of the big disadvantages of the EAV (anti) pattern you are using:
select a.value as name,
b.value as status,
c.value as city
from the_table a
join the_table b on a.element_id = b.element_id and b."key" = 'status'
join the_table c on a.element_id = c.element_id and c."key" = 'city'
where a."key" = 'name';
Another option is to aggregate all key/value pairs for an element into a JSON then you can easily access each one without additional joins:
select t.element_id,
t.obj ->> 'city' as city,
t.obj ->> 'status' as status,
t.obj ->> 'name' as name
from (
select e.element_id, jsonb_object_agg("key", value) as obj
from element e
group by e.element_id
) t;
If the table is really big this might be a lot slower than the join version due to the aggregation step. If you limit the query to only some elements (e.g. by adding a where element_id = 1
or where element_id in (1,2,3)
) then this should be quite fast.
It has the advantage that you always have all key/value pairs for each element_id available regardless on what you do. The inner select could be put into a view, to make things easier.
Online example: https://rextester.com/MSZOWU37182
One option is to simply add another join for each value you need (this is one of the big disadvantages of the EAV (anti) pattern you are using:
select a.value as name,
b.value as status,
c.value as city
from the_table a
join the_table b on a.element_id = b.element_id and b."key" = 'status'
join the_table c on a.element_id = c.element_id and c."key" = 'city'
where a."key" = 'name';
Another option is to aggregate all key/value pairs for an element into a JSON then you can easily access each one without additional joins:
select t.element_id,
t.obj ->> 'city' as city,
t.obj ->> 'status' as status,
t.obj ->> 'name' as name
from (
select e.element_id, jsonb_object_agg("key", value) as obj
from element e
group by e.element_id
) t;
If the table is really big this might be a lot slower than the join version due to the aggregation step. If you limit the query to only some elements (e.g. by adding a where element_id = 1
or where element_id in (1,2,3)
) then this should be quite fast.
It has the advantage that you always have all key/value pairs for each element_id available regardless on what you do. The inner select could be put into a view, to make things easier.
Online example: https://rextester.com/MSZOWU37182
answered Nov 23 '18 at 10:23
a_horse_with_no_namea_horse_with_no_name
297k46452548
297k46452548
add a comment |
add a comment |
Seems like you want to PIVOT
One way to do that is via conditional aggregation.
select
-- t.element_id,
max(case when t.key = 'name' then t.value end) as name,
max(case when t.key = 'status' then t.value end) as status,
max(case when t.key = 'city' then t.value end) as city
from the_table t
group by t.element_id;
db<>fiddle here
Or use crosstab:
select
-- element_id,
name,
status,
city
from crosstab (
'select t.element_id, t.key, t.value
from the_table t'
) as ct (element_id int, name varchar(30), status varchar(30), city varchar(30));
But if you do like those joins, here's a way
select
-- el.element_id,
nm.value as name,
st.value as status,
ci.value as city
from
(
select distinct t.element_id
from the_table t
where t.key in ('name','status','city')
) as el
left join the_table as nm on (nm.element_id = el.element_id and nm.key = 'name')
left join the_table as st on (st.element_id = el.element_id and st.key = 'status')
left join the_table as ci on (ci.element_id = el.element_id and ci.key = 'city');
add a comment |
Seems like you want to PIVOT
One way to do that is via conditional aggregation.
select
-- t.element_id,
max(case when t.key = 'name' then t.value end) as name,
max(case when t.key = 'status' then t.value end) as status,
max(case when t.key = 'city' then t.value end) as city
from the_table t
group by t.element_id;
db<>fiddle here
Or use crosstab:
select
-- element_id,
name,
status,
city
from crosstab (
'select t.element_id, t.key, t.value
from the_table t'
) as ct (element_id int, name varchar(30), status varchar(30), city varchar(30));
But if you do like those joins, here's a way
select
-- el.element_id,
nm.value as name,
st.value as status,
ci.value as city
from
(
select distinct t.element_id
from the_table t
where t.key in ('name','status','city')
) as el
left join the_table as nm on (nm.element_id = el.element_id and nm.key = 'name')
left join the_table as st on (st.element_id = el.element_id and st.key = 'status')
left join the_table as ci on (ci.element_id = el.element_id and ci.key = 'city');
add a comment |
Seems like you want to PIVOT
One way to do that is via conditional aggregation.
select
-- t.element_id,
max(case when t.key = 'name' then t.value end) as name,
max(case when t.key = 'status' then t.value end) as status,
max(case when t.key = 'city' then t.value end) as city
from the_table t
group by t.element_id;
db<>fiddle here
Or use crosstab:
select
-- element_id,
name,
status,
city
from crosstab (
'select t.element_id, t.key, t.value
from the_table t'
) as ct (element_id int, name varchar(30), status varchar(30), city varchar(30));
But if you do like those joins, here's a way
select
-- el.element_id,
nm.value as name,
st.value as status,
ci.value as city
from
(
select distinct t.element_id
from the_table t
where t.key in ('name','status','city')
) as el
left join the_table as nm on (nm.element_id = el.element_id and nm.key = 'name')
left join the_table as st on (st.element_id = el.element_id and st.key = 'status')
left join the_table as ci on (ci.element_id = el.element_id and ci.key = 'city');
Seems like you want to PIVOT
One way to do that is via conditional aggregation.
select
-- t.element_id,
max(case when t.key = 'name' then t.value end) as name,
max(case when t.key = 'status' then t.value end) as status,
max(case when t.key = 'city' then t.value end) as city
from the_table t
group by t.element_id;
db<>fiddle here
Or use crosstab:
select
-- element_id,
name,
status,
city
from crosstab (
'select t.element_id, t.key, t.value
from the_table t'
) as ct (element_id int, name varchar(30), status varchar(30), city varchar(30));
But if you do like those joins, here's a way
select
-- el.element_id,
nm.value as name,
st.value as status,
ci.value as city
from
(
select distinct t.element_id
from the_table t
where t.key in ('name','status','city')
) as el
left join the_table as nm on (nm.element_id = el.element_id and nm.key = 'name')
left join the_table as st on (st.element_id = el.element_id and st.key = 'status')
left join the_table as ci on (ci.element_id = el.element_id and ci.key = 'city');
edited Nov 23 '18 at 11:32
answered Nov 23 '18 at 10:23
LukStormsLukStorms
13k31733
13k31733
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53444419%2fjoin-three-rows-if-the-same-value-in-one-column%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
1
Simply add another JOIN. Keep the one and only WHERE at the end.
– jarlh
Nov 23 '18 at 10:06
@jarlh could you post the example?
– john bernat
Nov 23 '18 at 10:07
SELECT t1.c1, t2.cx ... FROM t1 JOIN t2 ON ... JOIN t3 ON ... WHERE...
– jarlh
Nov 23 '18 at 10:09