PostgreSQL select all from one table and join count from table relation - sql

I have two tables, post_categories and posts. I'm trying to select * from post_categories;, but also return a temporary column with the count for each time a post category is used on a post.
Posts
| id | name | post_category_id |
| 1 | test | 1 |
| 2 | nest | 1 |
| 3 | vest | 2 |
| 4 | zest | 3 |
Post Categories
| id | name |
| 1 | cat_1 |
| 2 | cat_2 |
| 3 | cat_3 |
Basically, I'm trying to do this without subqueries and with joins instead. Something like this, but in real psql.
select * from post_categories some-type-of-join posts, count(*)
Resulting in this, ideally.
| id | name | count |
| 1 | cat_1 | 2 |
| 2 | cat_2 | 1 |
| 3 | cat_3 | 1 |
Your help is greatly appreciated :D

You can use a derived table that contains the counts per post_category_id and left join it to the post_categories table
select p.*, coalesce(t1.p_count,0)
from post_categories p
left join (
select post_category_id, count(*) p_count
from posts
group by post_category_id
) t1 on t1.post_category_id = p.id

select post_categories.id, post_categories.name , count(posts.id)
from post_categories
inner join posts
on post_category_id = post_categories.id
group by post_categories.id, post_categories.name

Related

How do I receive a pair of ids of entities in many-to-many relation with null value for the second id if condition is not met

I've got the following tables: person (id), person_agency (person_id, agency_id) and agency(id, type)
this is my query:
select p.id, a.id from person p
left join person_agency pa on p.id = pa.person_id
left join agency a on pa.agency_id = a.id
where a.type = 'agency_type1'
However, with the query I get only the persons who have a relation with an agency of "agency_type1". Instead, I would like to get a list of ids of ALL persons with ids of agencies, where the relation exists and null where it doesn't. I tried naive outer joins but it did not work.
For this content of the tables:
Person:
+-------+
| id |
+-------+
| 1 |
| 2 |
| 3 |
| 4 |
+-------+
Person_agency:
+-----------+-----------+
| person_id | agency_id |
+-----------+-----------+
| 1 | 1 |
| 1 | 2 |
| 2 | 4 |
| 4 | 5 |
+-----------+-----------+
Agency:
+--------+------------------+
| id | type |
+--------+------------------+
| 1 | agency_type1 |
| 2 | some_other_type |
| 3 | agency_type1 |
| 4 | agency_type1 |
| 5 | some_other_type |
+--------+------------------+
I receive the folloing output of my query:
+----------+------+
| p.id | a.id |
+----------+------+
| 1 | 1 |
| 2 | 4 |
+----------+------+
The desired output would be:
+----------+------+
| p.id | a.id |
+----------+------+
| 1 | 1 |
| 2 | 4 |
| 3 | null |
| 4 | null |
+----------+------+
It looks like you don't want to distinguish between an agency which is missing and an agency which is present but the wrong type. So you would want a regular JOIN not a LEFT JOIN for the pa/a pair, and also want to filter out the unwanted type directly on that join. Then you want to do a LEFT JOIN from person to the results of that just-described join.
select p.id p_id, a.id a_id from person p
left join (person_agency pa join agency a on pa.agency_id = a.id and a.type='agency_type1')
on p.id = pa.person_id;
p_id | a_id
------+--------
1 | 1
2 | 4
3 | (null)
4 | (null)
The parenthesis around the join pair are not necessary but I find they make it clearer.
If one person is associated to multiple agencies of the correct type, all of them will be shown. I assume this is what you want, although it was not a scenario covered in your example data.
Try to change left join
to
join (inner join).

SQL generate Data based of the ids of three tables

I have three tables store, gender, age_group each of these tables have ids. I need to generate table data for each one all possible combinations of the three.
ex. store_id = (1,2,3) gender_id = (1,2,3) age_group_id = (1,2,3)
so that i have a table that looks like this:
|store_id|gender_id|age_group_id|
|:------:|:-------:|:----------:|
| 1 | 1 | 1 |
| 1 | 2 | 1 |
| 1 | 3 | 1 |
| 2 | 1 | 3 |
| 2 | 2 | 3 |
| 3 | 1 | 3 |
| 3 | 2 | 3 |
etc. continuing on until each combination is populated, any suggestions on best approach to do this in SQL
Cross join the three tables:
select
s.Id as store_id,
g.Id as gender_id,
a.Id as age_group_id
from store s
cross join gender g
cross join age_group a

Joining table on two columns only joins it on a single

How do I correctly join a table on two columns. My issue is that the result is not correct as it only joins on a single column.
This question started of in this other question: SQL query returns product of results instead of sum . I am creating a new question as there is an other issue I am trying to solve.
I join a table of materials on a table which contains multiple supply and disposal movements. Each movement references a material id. I would like to join the material on each movement.
My query:
SELECT supply_material_refer, disposal_material_refer, material_id, material_name
FROM "construction_sites"
JOIN projects ON construction_sites.project_refer = projects.project_id
JOIN addresses ON construction_sites.address_refer = addresses.address_id
cross join lateral ( select *
from (select row_number() over () as rn, *
from supplies
where supplies.supply_project_refer = projects.project_id) as supplies
full join (select row_number() over () as rn, *
from disposals
where disposals.disposal_project_refer = projects.project_id
) as disposals
on (supplies.rn = disposals.rn)
) as combined
LEFT JOIN materials material ON combined.disposal_material_refer = material.material_id
OR combined.supply_material_refer = material.material_id
WHERE (projects.project_name = 'Project 15')
ORDER BY construction_site_id asc;
The result of the query:
+-----------------------+-------------------------+-------------+---------------+
| supply_material_refer | disposal_material_refer | material_id | material_name |
+-----------------------+-------------------------+-------------+---------------+
| 1 | 1 | 1 | Materialtest |
| 2 | 1 | 1 | Materialtest |
| 2 | 1 | 2 | Dirt |
| 1 | 1 | 1 | Materialtest |
| 2 | 1 | 1 | Materialtest |
| 2 | 1 | 2 | Dirt |
| 1 | (null) | 1 | Materialtest |
| 4 | (null) | 4 | Stones |
+-----------------------+-------------------------+-------------+---------------+
An example line I have issues with:
+------------------------+-------------------------+-------------+---------------+
| supply_material_refer | disposal_material_refer | material_id | material_name |
+------------------------+-------------------------+-------------+---------------+
| 2 | 1 | 1 | Materialtest |
+------------------------+-------------------------+-------------+---------------+
A prefered output would be like:
+------------------------+----------------------+-------------------------+------------------------+
| supply_material_refer | supply_material_name | disposal_material_refer | disposal_material_name |
+------------------------+----------------------+-------------------------+------------------------+
| 2 | Dirt | 1 | Materialtest |
+------------------------+----------------------+-------------------------+------------------------+
I have created a sqlfiddle with dummy data: http://www.sqlfiddle.com/#!17/863d78/2
To my understanding the solution would be to have a disposal_material column and and supply_material column for the material names. I do not know how I can achieve this goal though...
Thanks for any help!

Access Queries comparing two tables

I have two tables in Access, Table A and Table B:
Table MasterLockInsNew:
+----+-------+----------+
| ID | Value | Date |
+----+-------+----------+
| 1 | 123 | 12/02/13 |
| 2 | 1231 | 11/02/13 |
| 4 | 1265 | 16/02/13 |
+----+-------+----------+
Table InitialPolData:
+----+-------+----------+---+
| ID | Value | Date |Type
+----+-------+----------+---+
| 1 | 123 | 12/02/13 | x |
| 2 | 1231 | 11/02/13 | x |
| 3 | 1238 | 10/02/13 | y |
| 4 | 1265 | 16/02/13 | a |
| 7 | 7649 | 18/02/13 | z |
+----+-------+----------+---+
All I want are the rows from table B for IDs not contained in A. My current code looks like this:
SELECT Distinct InitialPolData.*
FROM InitialPolData
WHERE InitialPolData.ID NOT IN (SELECT Distinct InitialPolData.ID
from InitialPolData INNER JOIN
MasterLockInsNew
ON InitialPolData.ID=MasterLockInsNew.ID);
But whenever I run this in Access it crashes!! The tables are fairly large but I don't think this is the reason.
Can anyone help?
Thanks
or try a left outer join:
SELECT b.*
FROM InitialPolData b left outer join
MasterLockInsNew a on
b.id = a.id
where
a.id is null
Simple subquery will do.
select * from InitialPolData
where id not in (
select id from MasterLockInsNew
);
Try using NOT EXISTS:
SELECT Distinct i.*
FROM InitialPolData AS i
WHERE NOT EXISTS (SELECT 1
FROM MasterLockInsNew AS m
WHERE m.ID = i.ID)

how to bake in a record count in a sql query

I have a query that looks like this:
select id, extension, count(distinct(id)) from publicids group by id,extension;
This is what the results looks like:
id | extension | count
-------------+-------------------------+-------
18459154909 | 12333 | 1
18459154909 | 9891114 | 1
18459154919 | 43244 | 1
18459154919 | 8776232 | 1
18766145025 | 12311 | 1
18766145025 | 1122111 | 1
18766145201 | 12422 | 1
18766145201 | 14141 | 1
But what I really want is for the results to look like this:
id | extension | count
-------------+-------------------------+-------
18459154909 | 12333 | 2
18459154909 | 9891114 | 2
18459154919 | 43244 | 2
18459154919 | 8776232 | 2
18766145025 | 12311 | 2
18766145025 | 1122111 | 2
18766145201 | 12422 | 2
18766145201 | 14141 | 2
I'm trying to get the count field to show the total number of records that have the same id.
Any suggestions would be appreciated
I think you want to count distincts extentions, not ids.
Run this query:
select id
, extension
(select count(*) from publicids p1 where p.id = p1.id ) distinct_id_count
from publicids p
group by id,extension;
This is more or less the same as Pastor's answer. Depending on what the optimizer does it might be faster with higher record count source tables.
select p.id, p.extension, p2.id_count
from publicids p
inner join (
select id, count(*) as id_count
from publicids group by id
) as p2 on p.id = p2.id