Reputation: 674
The use case is this: each user can create their own games, and keep track in which country they played a game.
I would like to create one query where I can get a list of all games for that user and in which country that game was played. I am only interested in the country id.
I have 4 tables: users, games, countries and a games_countries_xref table.
CREATE SEQUENCE countries_id_seq INCREMENT 1 MINVALUE 1 MAXVALUE 2147483647 START 1 CACHE 1;
CREATE TABLE "public"."countries" (
"id" integer DEFAULT nextval('countries_id_seq') NOT NULL,
"name" character varying(200) NOT NULL,
CONSTRAINT "countries_pkey" PRIMARY KEY ("id")
) WITH (oids = false);
INSERT INTO "countries" ("id", "name") VALUES
(1, 'USA'),
(2, 'Japan'),
(3, 'Australia');
CREATE SEQUENCE games_id_seq INCREMENT 1 MINVALUE 1 MAXVALUE 2147483647 START 3 CACHE 1;
CREATE TABLE "public"."games" (
"id" integer DEFAULT nextval('games_id_seq') NOT NULL,
"user_id" integer NOT NULL,
"name" character varying(200) NOT NULL,
CONSTRAINT "games_pkey" PRIMARY KEY ("id")
) WITH (oids = false);
INSERT INTO "games" ("id", "user_id", "name") VALUES
(1, 1, 'Monopoly'),
(2, 1, 'Zelda'),
(3, 2, 'Hide & Seek');
CREATE TABLE "public"."games_countries_xref" (
"game_id" integer NOT NULL,
"country_id" integer NOT NULL
) WITH (oids = false);
INSERT INTO "games_countries_xref" ("game_id", "country_id") VALUES
(1, 1),
(1, 2),
(1, 3),
(2, 2),
(3, 1);
CREATE SEQUENCE users_id_seq INCREMENT 1 MINVALUE 1 MAXVALUE 2147483647 START 2 CACHE 1;
CREATE TABLE "public"."users" (
"id" integer DEFAULT nextval('users_id_seq') NOT NULL,
"name" character varying(200) NOT NULL,
CONSTRAINT "users_pkey" PRIMARY KEY ("id")
) WITH (oids = false);
INSERT INTO "users" ("id", "name") VALUES
(1, 'Jack'),
(2, 'Jason');
when querying the data, I tried using ARRAY_AGG:
WITH country_ids AS (
SELECT g.user_id, ARRAY_AGG(gcx.country_id) AS country_ids
FROM games AS g
LEFT JOIN games_countries_xref AS gcx ON g.id = gcx.game_id
GROUP BY g.user_id
)
SELECT g.name, country_ids
FROM games AS g
NATURAL LEFT JOIN country_ids
WHERE g.user_id = 1
but that gives me this output:
name | country_ids
------------------
Monopoly | {1,2,3,2}
Zelda | {1,2,3,2}
while I am looking for this:
name | country_ids
------------------
Monopoly | {1,2,3}
Zelda | {2}
I know I am likely doing something wrong in the subquery, but I can't figure out what. Any ideas?
Upvotes: 0
Views: 49
Reputation: 14861
You are on the right track with ARRAY_AGG
, but just a little over aggressive with the joins. You just need a simple join (1 left, 1 inner) on the 3 tables
select g.name,array_agg(gcx.country_id) as country_ids
from games g
join users u on u.id = g.user_id
left join games_countries_xref gcx on gcx.game_id = g.id
where u.id = 1
group by g.name;
+----------+-------------+
| name | country_ids |
+----------+-------------+
| Monopoly | {1,2,3} |
| Zelda | {2} |
+----------+-------------+
Upvotes: 1