IDs in Two Columns - Find One ID and Retrieve Other ID - sql

This question has probably been asked before, but I haven't found it. I have a PostgreSQL table with IDs in two columns.
user_left | user_right |
-----------+------------
1 | 2 |
2 | 3 |
4 | 2 |
If I select user 2, I'd like to return something like:
users |
------+
1 |
3 |
4 |
I know I will have to join something, but what I've tried (inner joins, outer joins) baffles me. Any help or direction is appreciated.

Here is one method:
select user_left
from t
where user_right = 2
union all
select user_right
from t
where user_left = 2;
You can also use a case expression:
select (case when user_left = 2 then user_right else user_left end)
from t
where 2 in (user_left, user_right);

Related

Find SQL table rows where there are multiple different values

I want to be able to filter out groups where the values aren't the same. When doing the query:
SELECT
category.id as category_id,
object.id as object_id,
object.value as value
FROM
category,
object
WHERE
category.id = object.category
We get the following results:
category_id | object_id | value
-------------+-----------+-------
1 | 1 | 1
1 | 2 | 2
1 | 3 | 2
2 | 4 | 3
2 | 5 | 2
3 | 6 | 1
3 | 7 | 1
The goal: Update the query so that it yields:
category_id
-------------
1
2
In other words, find the categories where the values are different from the others in that same category.
I have tried many different methods of joining, grouping and so on, to no avail.
I know it can be done with multiple queries and then filter with a little bit of logic, but this is not the goal.
You can use aggregation:
SELECT o.category as category_id
FROM object o
GROUP BY o.category
HAVING MIN(o.value) <> MAX(o.value);
You have left the FROM clause out of your query. But as written, you don't need a JOIN at all. The object table is sufficient -- because you are only fetching the category id.

I need merge 2 lines in only one based on other column attribute name

I am stuck for some time in this. Imagine that I have this table:
diagId | astigmatic
1 | No
1 | Yes
2 | No
3 | No
4 | No
5 | No
5 | Yes
6 | No
And I want the output:
diagId | astigmatic
1 | Yes
2 | No
3 | No
4 | No
5 | Yes
6 | No
So if there is a diagId with Yes and No, I want the Yes tuple to pervail and the No tuple to disappear.
How can I achieve this?
Thanks!
One method is aggregation:
select diagid, max(astigmatic) as astigmatic
from t
group by diagid;
This works because 'yes' > 'no'.
Or, a conceptually similar method but one that is probably faster in Postgres:
select distinct on (diagid) t.*
from t
order by diagid, astigmatic desc;
Another approach is or and not exists:
select t.*
from t
where t.astigmatic = 'yes' or
(t.astigmatic = 'no' and
not exists (select 1
from t t2
where t2.id = t.id and
t2.astigmatic = 'yes'
)
);
The first two method return one row per id -- guaranteed. This last method could return multiple rows, if there are multiple 'yes's or 'no's for a given id.

Select and count in the same query on two tables

I've got these two tables:
___Subscriptions
|--------|--------------------|--------------|
| SUB_Id | SUB_HotelId | SUB_PlanName |
|--------|--------------------|--------------|
| 1 | cus_AjGG401e9a840D | Free |
|--------|--------------------|--------------|
___Rooms
|--------|-------------------|
| ROO_Id | ROO_HotelId |
|--------|-------------------|
| 1 |cus_AjGG401e9a840D |
| 2 |cus_AjGG401e9a840D |
| 3 |cus_AjGG401e9a840D |
| 4 |cus_AjGG401e9a840D |
|--------|-------------------|
I'd like to select the SUB_PlanName and count the rooms with the same HotelId.
So I tried:
SELECT COUNT(*) as 'ROO_Count', SUB_PlanName
FROM ___Rooms
JOIN ___Subscriptions
ON ___Subscriptions.SUB_HotelId = ___Rooms.ROO_HotelId
WHERE ROO_HotelId = 'cus_AjGG401e9a840D'
and
SELECT
SUB_PlanName,
(
SELECT Count(ROO_Id)
FROM ___Rooms
Where ___Rooms.ROO_HotelId = ___Subscriptions.SUB_HotelId
) as ROO_Count
FROM ___Subscriptions
WHERE SUB_HotelId = 'cus_AjGG401e9a840D'
But I get empty datas.
Could you please help ?
Thanks.
You need to use GROUP BY whenever you do some aggregation(here COUNT()). Below query will give you the number of ROO_ID only for the SUB_HotelId = 'cus_AjGG401e9a840D' because you have this condition in WHERE. If you want the COUNTs for all Hotel_IDs then you can simply remove the WHERE filter from this query.
SELECT s.SUB_PlanName, COUNT(*) as 'ROO_Count'
FROM ___Rooms r
JOIN ___Subscriptions s
ON s.SUB_HotelId = r.ROO_HotelId
WHERE r.ROO_HotelId = 'cus_AjGG401e9a840D'
GROUP BY s.SUB_PlanName;
To be safe, you can also use COUNT(DISTINCT r.ROO_Id) if you don't want to double count a repeating ROO_Id. But your table structures seem to have unique(non-repeating) ROO_Ids so using a COUNT(*) should work as well.

Access SQL Max-Function

I have a question concerning MS Access queries involving these tables:
tblMIDProcessMain ={ Process_ID,Process_Title,...}
tblMIDProcessVersion = { ProcessVersion_ID, ProcessVersion_FK_Process, ProcessVersion_VersionNo, ProcessVersion_FK_Status, ...}
tblMIDProcessVersionStatus = { ProcessVersionStatus_ID,ProcessVersionStatus_Value }
The tables store different versions of a process description. The "ProcessVersion_VersionNo" field contains an integer providing the version number. Now I would like to get for each process the highest version number thus the current version. If I do the following it kind of works:
SELECT tblMIDProcessMain.Process_Titel
, Max(tblMIDProcessVersion.ProcessVersion_VersionNo) AS CurrentVersion
FROM tblMIDProcessMain
INNER JOIN tblMIDProcessVersion
ON tblMIDProcessMain.Process_ID = tblMIDProcessVersion.ProcessVersion_FK_Process
GROUP BY tblMIDProcessMain.Process_Titel;
The query returns a recordset with each existing process_title and the respective max number of the version field. But as soon as I add other fields like "ProcessVersion_FK_Status" in the Select statement the query stops working.
Any help would be appreciated. Thanks in advance.
Jon
Edit:
To clarify things a little I added a simplified example
Parent-Table:
Process_ID | Process_Title
----------------------------------
1 | "MyProcess"
2 | "YourProcess"
Child-Table:
Version_ID | Version_FK_ProcessID | Version_No | Version_Status
---------------------------------------------------------------------------
1 | 1 | 1 | "New"
2 | 2 | 1 | "Discarded"
3 | 2 | 2 | "Reviewed"
4 | 2 | 3 | "Released"
Intended Result:
Title | Max_Version_No | Status
--------------------------------------------------------
MyProcess | 1 | "New"
YourProcess | 3 | "Released"
Given the example tables you updated your post with, this should work:
select process_title as Title
, max_version.max_version_no
, c.version_status as status
from (parenttable p
inner join (select max(version_id) as max_version_no, version_fk_process_id from childtable group by version_fk_process_id) max_version
on p.process_id = max_version.version_fk_process_id)
inner join childtable c
on max_version.max_version_no = c.version_id and max_version.version_fk_process_id = c.version_fk_process_id
I assume you are adding the new field to the 'Group By" clause? If not, then you either must include in the 'Group By', or you must use one of the operators like "Max" or "First" etc.

Finding the difference between two sets of data from the same table

My data looks like:
run | line | checksum | group
-----------------------------
1 | 3 | 123 | 1
1 | 7 | 123 | 1
1 | 4 | 123 | 2
1 | 5 | 124 | 2
2 | 3 | 123 | 1
2 | 7 | 123 | 1
2 | 4 | 124 | 2
2 | 4 | 124 | 2
and I need a query that returns me the new entries in run 2
run | line | checksum | group
-----------------------------
2 | 4 | 124 | 2
2 | 4 | 124 | 2
I tried several things, but I never got to a satisfying answer.
In this case I'm using H2, but of course I'm interested in a general explanation that would help me to wrap my head around the concept.
EDIT:
OK, it's my first post here so please forgive if I didn't state the question precisely enough.
Basically given two run values (r1, r2, with r2 > r1) I want to determine which rows having row = r2 have a different line, checksum or group from any row where row = r1.
select * from yourtable
where run = 2 and checksum = (select max(checksum)
from yourtable)
Assuming your last run will have the higher run value than others, below SQL will help
select * from table1 t1
where t1.run in
(select max(t2.run) table1 t2)
Update:
Above SQL may not give you the right rows because your requirement is not so clear. But the overall idea is to fetch the rows based on the latest run parameters.
SELECT line, checksum, group
FROM TableX
WHERE run = 2
EXCEPT
SELECT line, checksum, group
FROM TableX
WHERE run = 1
or (with slightly different result):
SELECT *
FROM TableX x
WHERE run = 2
AND NOT EXISTS
( SELECT *
FROM TableX x2
WHERE run = 1
AND x2.line = x.line
AND x2.checksum = x.checksum
AND x2.group = x.group
)
A slightly different approach:
select min(run) run, line, checksum, group
from mytable
where run in (1,2)
group by line, checksum, group
having count(*)=1 and min(run)=2
Incidentally, I assume that the "group" column in your table isn't actually called group - this is a reserved word in SQL and would need to be enclosed in double quotes (or backticks or square brackets, depending on which RDBMS you are using).