PostgreSQL and inheritance [duplicate] - postgresql

This question already has answers here:
Find Parent Recursively using Query
(2 answers)
Closed 3 years ago.
I have a table with this format:
Table name : identities
code |parent_code|
_______|___________|
AAA | Null |
AAB | AAA |
AAC | Null |
AAD | AAC |
AAE | AAB |
And I need a way to obtain the highest parent of any "code" in the table.
For instance, if I wanted to get the highest parent of the "code" AAE I would get as a result AAA, since the parent of AAE is AAB and the parent of AAB is AAA, and AAA would be the highest because it has no parent assosiated.
My problem is that I can´t modify the tables and I don´t know how to use "with recursive".
Thank you in advance.

You can use a recursive cte as follows:
with recursive cte as (
select code, parent_code, 1 lvl from identities where code = 'AAE'
union all
select i.code, i.parent_code, lvl + 1
from identities i
inner join cte c on c.parent_code = i.code
)
select code
from cte
where lvl = (select max(lvl) from cte)
Demo on DB Fiddle:
| code |
| :--- |
| AAA |

Related

Join Table with Unnested Array in postgres

I have a table of contacts and a study to with which they are associated. Now I am being passed an array of integers, representing contact_id. I need to join the current table of contacts with an unnested array of ids and delete the record if the unnested integer matches contact_id.
I have this so far
SELECT cvs.contact_id, cvs.study_id
FROM study.contacts_vs_studies AS cvs
LEFT JOIN (SELECT UNNEST('{1,2,3,4,68}'::INT[])) AS old_ids
ON cvs.contact_id = old_ids.old_ids
WHERE study_id = 6
This just returns all the available contacts for the study and nothing from the unnested array.
How can get a result of unnested array that matches select from existing table? TY
I think that your query does what you want. But you cannot see it since you are doing a left join and not selecting anything from the unnested array.
Consider this sample data:
contact_id | study_id
---------: | -------:
1 | 1
2 | 2
5 | 5
Now if we run the following query:
select cvs.contact_id, cvs.study_id, old_ids.old_ids
from contacts_vs_studies as cvs
left join unnest('{1,2,3,4,68}'::int[]) as old_ids
on cvs.contact_id = old_ids.old_ids
We get:
contact_id | study_id | old_ids
---------: | -------: | ------:
1 | 1 | 1
2 | 2 | 2
5 | 5 | null
Now you can see that the third record was not matched. To filter only on matching records, you can use an inner join instead of a left join.
select cvs.contact_id, cvs.study_id
from contacts_vs_studies as cvs
inner join unnest('{1,2,3,4,68}'::int[]) as old_ids
on cvs.contact_id = old_ids.old_ids
contact_id | study_id
---------: | -------:
1 | 1
2 | 2
Alternatively, if you want only non-matching records:
select cvs.contact_id, cvs.study_id
from contacts_vs_studies as cvs
left join unnest('{1,2,3,4,68}'::int[]) as old_ids
on cvs.contact_id = old_ids.old_ids
where old_ids.old_ids is null
contact_id | study_id
---------: | -------:
5 | 5
I need to join the current table of contacts with an unnested array of ids and delete the record if the unnested integer matches contact_id.
Sounds like you don't need a JOIN at all. Just write the DELETE command directly:
DELETE FROM study.contacts_vs_studies AS cvs
WHERE cvs.contact_id = ANY('{1,2,3,4,68}'::INT[])
AND cvs.study_id = 6

PostgreSQL Group By not working as expected - wants too many inclusions

I have a simple postgresql table that I'm tying to query. Imaging a table like this...
| ID | Account_ID | Iteration |
|----|------------|-----------|
| 1 | 100 | 1 |
| 2 | 101 | 1 |
| 3 | 100 | 2 |
I need to get the ID column for each Account_ID where Iteration is at its maximum value. So, you'd think something like this would work
SELECT "ID", "Account_ID", MAX("Iteration")
FROM "Table_Name"
GROUP BY "Account_ID"
And I expect to get:
| ID | Account_ID | MAX(Iteration) |
|----|------------|----------------|
| 2 | 101 | 1 |
| 3 | 100 | 2 |
But when I do this, Postgres complains:
ERROR: column "ID" must appear in the GROUP BY clause or be used in an aggregate function
Which, when I do that it just destroys the grouping altogether and gives me the whole table!
Is the best way to approach this using the following?
SELECT DISTINCT ON ("Account_ID") "ID", "Account_ID", "Iteration"
FROM "Marketing_Sparks"
ORDER BY "Account_ID" ASC, "Iteration" DESC;
The GROUP BY statement aggregates rows with the same values in the columns included in the group by into a single row. Because this row isn't the same as the original row, you can't have a column that is not in the group by or in an aggregate function. To get what you want, you will probably have to select without the ID column, then join the result to the original table. I don't know PostgreSQL syntax, but I assume it would be something like the following.
SELECT Table_Name.ID, aggregate.Account_ID, aggregate.MIteration
(SELECT Account_ID, MAX(Iteration) AS MIteration
FROM Table_Name
GROUP BY Account_ID) aggregate
LEFT JOIN Table_Name ON aggregate.Account_ID = Table_Name.Account_ID AND
aggregate.MIteration = Tabel_Name.Iteration

How to use COUNT() in more that one column?

Let's say I have this 3 tables
Countries ProvOrStates MajorCities
-----+------------- -----+----------- -----+-------------
Id | CountryName Id | CId | Name Id | POSId | Name
-----+------------- -----+----------- -----+-------------
1 | USA 1 | 1 | NY 1 | 1 | NYC
How do you get something like
---------------------------------------------
CountryName | ProvinceOrState | MajorCities
| (Count) | (Count)
---------------------------------------------
USA | 50 | 200
---------------------------------------------
Canada | 10 | 57
So far, the way I see it:
Run the first SELECT COUNT (GROUP BY Countries.Id) on Countries JOIN ProvOrStates,
store the result in a table variable,
Run the second SELECT COUNT (GROUP BY Countries.Id) on ProvOrStates JOIN MajorCities,
Update the table variable based on the Countries.Id
Join the table variable with Countries table ON Countries.Id = Id of the table variable.
Is there a possibility to run just one query instead of multiple intermediary queries? I don't know if it's even feasible as I've tried with no luck.
Thanks for helping
Use sub query or derived tables and views
Basically If You You Have 3 Tables
select * from [TableOne] as T1
join
(
select T2.Column, T3.Column
from [TableTwo] as T2
join [TableThree] as T3
on T2.CondtionColumn = T3.CondtionColumn
) AS DerivedTable
on T1.DepName = DerivedTable.DepName
And when you are 100% percent sure it's working you can create a view that contains your three tables join and call it when ever you want
PS: in case of any identical column names or when you get this message
"The column 'ColumnName' was specified multiple times for 'Table'. "
You can use alias to solve this problem
This answer comes from #lotzInSpace.
SELECT ct.[CountryName], COUNT(DISTINCT p.[Id]), COUNT(DISTINCT c.[Id])
FROM dbo.[Countries] ct
LEFT JOIN dbo.[Provinces] p
ON ct.[Id] = p.[CountryId]
LEFT JOIN dbo.[Cities] c
ON p.[Id] = c.[ProvinceId]
GROUP BY ct.[CountryName]
It's working. I'm using LEFT JOIN instead of INNER JOIN because, if a country doesn't have provinces, or a province doesn't have cities, then that country or province doesn't display.
Thanks again #lotzInSpace.

Count rows from a related table

I have the following query to gather data for a report:
SELECT COUNT(*) as inspected,
count(*) filter(where status='fail') as failed,
count(*) filter(where status='deficient') as impaired,
count(*) filter(where status='pass') as passed,
device_types.name
FROM inspection_data
INNER JOIN devices ON devices.id=inspection_data.device_id
INNER JOIN device_types ON devices.device_type_id=device_types.id
WHERE inspection_id = 3
GROUP BY device_types.id
ORDER BY device_types.name
This query is working as intended (Though I'm sure could be optimized somewhat. SQL isn't my strong suit). The problem is that I now want to gather one more summary datum. I want to count the number of each device_type_id in the devices table for this location_id.
I'll try to map out the database tables:
| devices | device_types | inspection_data |
|:--------------:|:------------:|:---------------:|
| id | id | id |
| device_type_id | name | inspection_id |
| location_id | | device_id |
| | | status |
So when I run the query, I'm receiving results similar to this:
| inspected | failed | impaired | passed | name |
|:---------:|:------:|:--------:|--------|----------------------------|
| 6 | 0 | 2 | 4 | Air Sampling Type Detector |
| 9 | 1 | 1 | 7 | Alarm Bell |
And this is great. My hangup is that not all devices for a location have to be inspected during an inspection. So for example, let's say there are actually 15 "Alarm Bell" devices for this location, but only 9 were inspected as part of this inspection, as per the table above. How do I go about including another column in this output, named "total" with a value of 15 for the Alarm Bell device type, and so on for each of the device types in the report?
I hope I've adequately described what I'm trying to do. I am utterly stumped on how to go about this without running a second query, and I really don't want to do that unless absolutely necessary because it just clutters the code up even more.
I think you want a left join. However, I'm not sure what table goes first. My best guess is:
SELECT COUNT(*) as total,
COUNT(id.device_id) as inspected,
COUNT(id.device_id) filter (where status='fail') as failed,
COUNT(id.device_id) filter (where status='deficient') as impaired,
COUNT(id.device_id) filter (where status='pass') as passed,
dt.name
FROM devices d INNER JOIN
device_types dt
ON d.device_type_id = dt.id LEFT JOIN
inspection_data id
ON d.id = id.device_id AND
id.inspection_id = 3
GROUP BY dt.id
ORDER BY dt.name

Find all multipolygons from one table within another

So, I've got two tables - PLUTO (pieces of land), and NYZMA (rezoning boundaries). They look like:
pluto nyzma
id | geom name | geom
-------------------- -------------------
1 | MULTIPOLYGON(x) A | MULTIPOLYGON(a)
2 | MULTIPOLYGON(y) B | MULTIPOLYGON(b)
And I want it to spit out something like this, assuming that PLUTO record 1 is in multipolygons A and B, and PLUTO record 2 is in neither:
pluto_id | nyzma_id
-------------------
1 | [A, B]
2 |
How do I, for every PLUTO record's corresponding geometry, cycle through each NYZMA record, and print the names of any whose geometry matches?
Join the two tables using the spatial function ST_Contains. Than use GROUP BY and ARRAY_AGG in the main query:
WITH subquery AS (
SELECT pluto.id, nyzma.name
FROM pluto LEFT OUTER JOIN nyzma
ON ST_Contains(nyzma.geom, pluto.geom)
)
SELECT id, array_agg(name) FROM subquery GROUP BY id;