postgresql : join with condition and without duplication - sql

I have a table A that contains a series of unique id. I have an other table B that contains some of this id but not each one of them, a field called value and a another field called idcategory. In this table B, id can appears several times because of differents categories.
I want to list all my id in the table A in a unique way and the specific value associated in the table B in a defined categorie (idcategorie = 1). Id in the table A could not appear in the table B, but i want this information anyway in my final result and without duplication.
Here is an illustration :
Table A
id
-----
1
2
3
4
5
6
7
8
Table B
id | idcategory | value
------------------------
1 | 1 | red
1 | 2 | circle
2 | 1 | green
3 | 1 | blue
3 | 2 | square
4 | 1 | green
4 | 2 | circle
5 | 1 | red
5 | 2 | square
8 | 2 | circle
Result
id | idcategory | value
------------------------
1 | 1 | red
2 | 1 | green
3 | 1 | blue
4 | 1 | green
5 | 1 | red
6 | null | no value
7 | null | no value
8 | null | no value
What is the best way to achieve this in postgreSQL ? LEFT JOIN ? UNION ?

You seem to want a left join:
select a.id, b.idcategory, b.value
from a left join
b
on b.id = a.id and b.idcategory = 1;
The value column has NULL rather than 'no value'. You can replace it, but NULL usually serves that purpose.

Related

SQL: how to add a column that works as a composite key with another column

I have an SQL table that looks like this:
ID | Category
1 | A
2 | A
3 | B
4 | C
5 | A
6 | C
7 | B
8 | A
And I want to add a column that works as an inner ID for each Category such that Category and the new column could work as a composite key. The new column should look like this:
ID | Category | Inner ID
1 | A | 1
2 | A | 2
3 | B | 1
4 | C | 1
5 | A | 3
6 | C | 2
7 | B | 2
8 | A | 4
How can I write a query to achieve that?
You need to give a sequential order in partitions based Category and ordered by ID. This can be achieved using the row_number() window function.
SELECT
*,
ROW_NUMBER() OVER(PARTITION BY Category ORDER BY ID) as [Inner ID]
FROM
Table
ORDER BY
ID

Query returned with an extra column in sql -ms access

So I am wondering. I fell into an interesting suggestion from another developer. So i basically have two tables I join in a query and I want the resulting table from the query to have an extra column that comes from the table on from the joint.
Example:
#table A: contains rating of players, changes randomly at any date depending
#on drop of form from the players
PID| Rating | DateChange |
1 | 2 | 10-May-2014 |
1 | 4 | 20-May-2015 |
1 | 20 | 1-June-2015 |
2 | 4 | 1-April-2014|
3 | 4 | 5-April-2014|
2 | 3 | 3-May-2015 |
#Table B: contains match sheets. Every player has a different match sheet
#and plays different dates.
MsID | PID | MatchDate | Win |
1 | 2 | 10-May-2014 | No |
2 | 1 | 15-May-2015 | Yes |
3 | 3 | 10-Apr-2014 | No |
4 | 1 | 21-Apr-2015 | Yes |
5 | 1 | 3-June-2015 | Yes |
6 | 2 | 5-May-2015 | No |
#I am trying to achieve this by running the ms-access query: i want to get
#every players rating at the time the match was played not his current
#rating.
MsID | PID | MatchDate | Rating |
1 | 2 | 10-May-2014 | 4 |
2 | 1 | 15-May-2015 | 2 |
3 | 3 | 10-Apr-2014 | 4 |
4 | 1 | 21-Apr-2015 | 4 |
5 | 1 | 3-June-2015 | 20 |
6 | 2 | 5-May-2015 | 3 |
This is what I have tried below:
Select MsID, PID, MatchDate, A-table.rating as Rating from B-table
left Join A-table
on B-table.PID = A-table.PID
where B-table.MatchDate > A-table.Datechange;
any help is appreciated. The solution can be in Vba as long as it returns something like a view/table I can manipulate using other queries or report.
Think of this in terms of sets of data... you need a set that lists the MAX dateChange for each player's and match date.
Soo...
SELECT MAX(A.DateChange) MDC, A.PID, B.Matchdate
FROM B-table B
INNER Join A-table A
on B.PID = A.PID
and A.DateChange <= B.MatchDate
GROUP BY A.PID, B.Matchdate
Now we take this and join it back to what you've done to limit the results in table A and B to ONLY those with that date player and matchDate (my inline table C)
SELECT B.MsID, B.PID, B.MatchDate, A.rating as Rating
FROM [B-table] B
INNER JOIN [A-table] A
on B.PID = A.PID
INNER JOIN (
SELECT MAX(Y.DateChange) MDC, Y.PID, Z.Matchdate
FROM [B-table] Z
INNER Join [A-table] Y
on Z.PID = Y.PID
and Y.DateChange <= Z.MatchDate
GROUP BY Y.PID, Z.Matchdate) C
on C.mdc = A.DateChange
and A.PID = C.PId
and B.MatchDate = C.Matchdate
I didn't create a sample for this using your data so it's untested but I believe the logic is sound...
Now Tested! SQL Fiddle using SQL server though...
My results don't match yours exactly. I think you're expected results are wrong though for MSID 4 given rules defined.

Exclude a group when one row match in another table

I have two tables :
the first one called "card" with one column "id".
| id |
| 1 |
| 2 |
| 3 |
| .. |
The second table is named "waste" with two columns "card_id" and "waste_type".
| card_id | waste_type |
| 1 | 1 |
| 1 | 3 |
| 2 | 2 |
| 2 | 1 |
And i want to select only the card where there is no waste_type = 2
The query should look like this :
SELECT c.id FROM card c
JOIN waste w
ON c.id = w.card_id
WHERE waste_type <> 2
I want this result :
id
1
But i get :
id
1
2
How can i do that ? Thank you so much in advance !
You should use a not exists clause for that.
select c.id
from card c
where not exists (select null from waste w
where w.card_id = c.id
and w.waste_type = 2)
With your query, I would guess you rather retrieve
1
1
2

find set of row, duplicate list, before insert

I have table (it's a list of struct with 4 integers, first id is list id)
id | idL | idA(null) | idB(null) | idC
1 | 1 | 2 | null | 1
2 | 1 | 4 | null | 1
3 | 1 | null | 1 | 1
4 | 2 | 2 | null | 1
5 | 2 | 4 | null | 1
6 | 3 | 6 | null | 1
7 | 3 | null | 4 | 1
Now I need to insert 4th list to this table
idA | idB | idC
2 | null | 1
4 | null | 1
null | 1 | 1
but, it's already exist (list id = 1)
idA | idB | idC
2 | null | 1
4 | null | 1
alse exist (idL = 2)
idA | idB | idC
2 | null | 1
4 | null | 1
null | 7 | 1
does not exist.
How to find duplicate before insert it to table
It appears to be just a matter of insert from (select not in).
Try this example:
SQLFiddle
Disclaimer: In the example data you provided rows 2 and 4 got a identical idA,idB,idC set.
If that columns cannot form a unique and you already got that tuple in copy table and you need one row in copy table for each row in original table that ill be a lot harder because for a such row in copy there's no way to tell the row in original it's related.
if values is in table temp and you know the list id.
you can use "Except"
eg:
insert into list (idL, idA, idB, idC)
select #list_id, t.idA, t.idB, t.idC
from
(
select idA, idB, idC
from #new_values
except
select idA, idB, idC
from list
) t

Is there a way to sort by hierarchy when the result set comes from a self referencing table?

We've got an Oracle self-referencing table to represent a hierarchy similar to:
THING
---------
ID
PARENT_ID
NAME
SOME_DATA
The top-level THING has a null PARENT_ID.
I'd like to be able to select from this table and order my data by each row's position in the hierarchy (from top to bottom) and then by name such that the data set:
ID PARENT_ID NAME SOME_DATA
1 null top null
2 1 cat null
3 1 dog null
4 2 frog null
5 1 bird null
6 2 fish null
... becomes:
ID PARENT_ID NAME SOME_DATA
1 null top null
5 1 bird null
2 1 cat null
6 2 fish null
4 2 frog null
3 1 dog null
When I started typing this question, I was curious as to any whether or not there was a way to do this without adding a LEVEL column to the table but now I'm not even certain it can be done by adding that column.
A 'no' answer is perfectly acceptable here as I'm already resigned to the fact that I'm going to have to do this in my Java code.
Instead of using LEVEL and trying to manage the results in a clever way, it's possible to use START WITH and ORDER SIBLINGS BY to get the result you're looking for:
SQL Fiddle
SELECT t.*
FROM thing t
CONNECT BY PRIOR t.id = t.parent_id
START WITH t.parent_id IS NULL
ORDER SIBLINGS BY t.name
Results:
| ID | PARENT_ID | NAME | SOME_DATA |
-------------------------------------
| 1 | (null) | top | (null) |
| 5 | 1 | bird | (null) |
| 2 | 1 | cat | (null) |
| 6 | 2 | fish | (null) |
| 4 | 2 | frog | (null) |
| 3 | 1 | dog | (null) |
This chains through the hierarchy, starting with the root (parent_id IS NULL) and orders the results.