I have this table (say TABLE1):
ID1 | ID2 | NAME
where (ID1, ID2) is the composite PK.
And this another table (say TABLE2):
ID | COD1 | COD2 | DATA | INDEX
where ID is the PK.
I need to join this tables on ((TABLE1.ID1 = TABLE2.COD1) AND (TABLE1.ID2 = TABLE2.COD2))
My problem is that, for each ID of TABLE2, I have many tuples with different INDEX. I only want join the tuple that its INDEX is the MAX of its group (COD1, COD2).
For instance, if I have:
ID1|ID2|NAME
10 10 JOSH
ID|COD1|COD2|DATA|INDEX
1 10 10 YES 0
2 10 10 NO 1
3 11 10 OH 0
I want to get:
ID1|ID2|NAME|DATA
10 10 JOSH NO
I have tried this but it doesn't work:
SELECT ID1, ID2, NAME, DATA
FROM TABLE1 T1 JOIN TABLE2 T2 ON T1.ID1 = T2.COD1 AND T1.ID2 = T2.COD2
GROUP BY ID1, ID2, NAME, DATA HAVING INDEX = MAX(INDEX)
Thanks.
This is the generic construct.
select field1,field2, etc
from yourtables
join
(select field1, max(something) themax
from table1
where whatever
group by field1) temp on table1.something = themax
and table1.field1 = temp.field1
where whatever
The two "where whatevers" should be the same. You should be able to take it from here.
A slightly different solution:
select t1.id1, t1.id2, t1."NAME", t3."DATA"
from table1 t1
left join
(
select max("INDEX") as maxindex, cod1, cod2
from table2
group by cod1, cod2
) tt on tt.cod1 = t1.id1 and tt.cod2 = t1.id2
left join table2 t2 on t2."INDEX" = tt.maxindex;
If all tuples have different and unique values INDEX, these example is OK. But if some tuples have the same value, it is necessary to write an additional subquery (e.g. select max(ID) from table2) to determine appropriate lines.
P.S. It's best not to use any keyword for your own tables or columns (e.g. INDEX, DATA ...).
How To Handle Table Column Named With Reserved Sql Keyword?
Got an Oracle Table Named as Reserved Word, Which problems may arise?
try
SELECT ID1,ID2,NAME
FROM TABLE1
join
(select ID,DATA, max(Index) themax
FROM TABLE2
WHERE (your condition)
group by ID) temp on table1.Index = themax
WHERE (your condition)
I have solved it this way:
SELECT ... FROM TABLE1 JOIN
(SELECT ID1, ID2, NAME, DATA
FROM TABLE1 T1 JOIN TABLE2 T2 ON T1.ID1 = T2.COD1 AND T1.ID2 = T2.COD2
GROUP BY ID1, ID2, NAME, DATA HAVING INDEX = SELECT MAX(INDEX) FROM TABLE2 WHERE TABLE1.ID1 = TABLE2.COD1 AND TABLE1.ID2 = TABLE2.COD2
Thanks!
Related
I need to create a table keyed by an ID where the values of one of the columns in the new table are the earliest values entered into the column of another table where the rows share the same ID and have a specific type label.
For example, say I want the Name and first Value entered for each fruit with an entry type A:
These are the tables I have:
TABLE1
Key
ID
Name
1
1
Cherry
2
2
Grape
TABLE2
Key
ID
Value
EntryNum
EntryType
1
1
21
1
A
2
1
32
2
B
3
1
4
3
B
4
1
15
4
A
5
2
3
1
B
6
2
8
2
A
7
2
16
3
B
And this is the result that I want:
TABLE3
ID
Name
EarliestEntry
1
Cherry
21
2
Grape
8
I've attempted the following query but it just returns the same value for all EarliestEntry:
SELECT TABLE1.ID, TABLE2.Name,
(SELECT Value FROM (SELECT ROW_NUMBER() OVER (ORDER BY TABLE2.EntryNum)
as row_num, Value FROM TABLE2
WHERE TABLE2.ID = TABLE1.ID AND TABLE2.EntryType = 'A')
AS sub
WHERE row_num = 1) AS EarliestEntry
INTO TABLE3
FROM TABLE2
INNER JOIN TABLE1 ON TABLE1.ID = TABLE2.ID
GROUP BY TABLE1.ID, TABLE2.Type, TABLE2.EntryNum
I would greatly appreciate help on this. Thank you
If you wanted to use the ROW_NUMBER function then you would need to put that on TABLE1 and add a partition by like so:
WITH rn AS(
SELECT a.Key, ROW_NUMBER() OVER(PARTITION BY a.ID ORDER BY a.EntryNum) AS rn
FROM TABLE2 AS a
)
SELECT b.Name, a.Value AS EarliestValue
FROM TABLE2 AS a
INNER JOIN TABLE1 AS b ON b.ID = a.ID
INNER JOIN rn AS rn ON rn.key = a.key
WHERE rn.rn = 1
In your example you skipped the PARTITION BY clause so you just get a number for all values in TABLE2. Instead of a number per ID in ascending order for Value.
Based on your description of the three tables TABLE1, TABLE2 and TABLE3.
I modified a little bit your script. Thank of Dale K remark, I explain in some words the solution : the field TABLE2.Name shown in the first select was wrong, because [name] belongs to TABLE1, so the right syntax for this is TABLE1.name. And in the GROUP BY clause the field TABLE2.Type might be replaced by TABLE1.name to repect aggregation criteria. So the script becomes :
SELECT DISTINCT table1.id, table1.name,
(SELECT Value FROM (SELECT ROW_NUMBER() OVER (ORDER BY table2.EntryNum)
as row_num, Value FROM table2
WHERE table2.id = table1.id AND table2.EntryType = 'A')
AS sub
WHERE row_num = 1) AS EarliestEntry
INTO table3
FROM table2
INNER JOIN table1 ON table1.id = table2.id
GROUP BY table1.id, table1.name, table2.entrynum;
Here, you can verify the output with fiddle
You are hugely over-complicating this.
Just partition Table2 and take a row-number, then join that to Table1 and filter on only row-number 1
SELECT
t1.Id,
t1.Name,
EarliestEntry = t2.Value
FROM Table1 t1
JOIN (
SELECT *,
rn = ROW_NUMBER() OVER (PARTITION BY t2.ID ORDER BY t2.EntryNum)
FROM Table2 t2
WHERE t2.EntryType = 'A'
) t2 ON t2.ID = t1.ID AND t2.rn = 1;
db<>fiddle
Using an Oracle 11g DB, I am looking for a way to consolidate two rows from one table into a single row on my query result, but also allow NULL values where data has not been entered.
Basically I have something like:
TABLE1 contains object identification
TABLE2 contains two rows for object data (type A & B)
I was thinking I'd need to run an OUTER JOIN, which works when only getting object data type A, but when when I add a second JOIN, I get multiple repeated lines of A for each line of B.
So if there are 4 A values and 5 B values, I will see 5 rows of A for each row of B (20 rows in total)
SELECT T1.NAME, T2a.VALUE as TYPE_A, T2b.VALUE as TYPE_B
FROM TABLE1 T1
LEFT OUTER JOIN TABLE2 T2a ON (T1.ID = T2a.ID AND T2a.TYPE='A')
LEFT OUTER JOIN TABLE2 T2b ON (T1.ID = T2b.ID AND T2b.TYPE='B')
I'm wanting to get this (see how A has 6 entries, B has 5):
NAME TYPE_A TYPE_B
ID1 VALUE1 VALUE2
ID1 VALUE1 VALUE2
ID1 VALUE1 (NULL)
ID1 VALUE1 VALUE2
ID1 (NULL) VALUE2
ID1 VALUE1 (NULL)
ID1 (NULL) VALUE2
ID1 VALUE1 (NULL)
Any help would be greatly appreciated.
KS
Would a Pivot work?
Note Pivot only works if you know all the values of Type that you want. If it's not known, then you have to use dynamic SQL..
SELECT *
FROM
(
SELECT Name, Type, Value
FROM Table1 T1
INNER JOIN table2 T2
ON T1.ID = T2.ID
)
PIVOT
(
MAX(Value)
FOR (Type) IN ('A' AS TYPE_A,
'B' AS Type_B)
);
PIVOT should work here
SQL Fiddle: http://www.sqlfiddle.com/#!4/46004f/2
SELECT *
FROM (SELECT T1.ID, T2.type, T2.value
FROM table1 T1
JOIN table2 T2
ON T1.ID = T2.ID)
PIVOT
( MAX(value) FOR type in ('A', 'B')
)
I have a table with the following structure:
ID KEY VALUE SEQ
1 Amount 5 2
1 Amount 4 1
1 Type T1 2
1 Type T1 1
2 Amount 10 2
2 Amount 5 1
2 Type T2 2
2 Type T2 1
I would like to create a query to get this:
ID Amount Type
1 5 T1
2 10 T2
As you can see there could be multiple combinations of (ID, Key) but (ID, Key, Seq) is unique.
SELECT T.ID,
T1.VALUE as Amount,
T2.VALUE as Type
FROM
(SELECT ID, MAX(SEQ) as MAXSEQ FROM TABLE GROUP BY ID) as T
JOIN
TABLE as T1
ON T1.ID = T.ID
AND T1.KEY = 'Amount'
AND T1.SEQ = MAXSEQ
JOIN
TABLE as T2
ON T2.ID = T.ID
AND T2.KEY = 'Type'
AND T2.SEQ = MAXSEQ
But I am getting results that I wasn't expecting
ID Amount Type
1 5 T1
1 4 T1
1 10 T1
1 5 T1
2 10 T2
2 5 T2
2 4 T2
2 5 T2
I already read this post but it doesn't apply to my case although it helps here
Any idea on who to fix this?
SELECT
id, amount, type
FROM TABLE1
natural join (SELECT ID, MAX(SEQ) as SEQ FROM TABLE1 GROUP BY ID)
pivot (
max(VALUE) for key in ('Amount' as amount, 'Type' as type)
)
fiddle
Something you are missing from the linked question is the DISTINCT keyword.
See also the explanation below the query posted by ypercube. In fact, you are getting duplicates because you are joining a table on itself. Thus, rows will be mirrorred.
Your subquery should be:
(SELECT DISTINCT ID, MAX(SEQ) as MAXSEQ FROM TABLE GROUP BY ID) as T
I realized that there was another column, that I didn't put in the question (to avoid giving out real data)which was affecting the results. The unique constraint was (ID, Key, Seq, Time) instead of (ID, Key, Seq). As #Andrew Mentioned the query is returning the correct results.
Here goes the query again
SELECT T.ID,
T1.VALUE as Amount,
T2.VALUE as Type
FROM
(SELECT ID, MAX(SEQ) as MAXSEQ FROM TABLE GROUP BY ID) as T
JOIN
TABLE as T1
ON T1.ID = T.ID
AND T1.KEY = 'Amount'
AND T1.SEQ = MAXSEQ
JOIN
TABLE as T2
ON T2.ID = T.ID
AND T2.KEY = 'Type'
AND T2.SEQ = MAXSEQ
Thanks Andrew for the clarification and the sqlfiddle. I apologize if I wasted anyone's time.
Some data would be organized thusly:
ID DATE COUNT1 COUNT2
A 20120101 1 2
A 20120201 2 2
B 20120101 3 0
C 20111201 1 0
C 20120301 2 2
Another table has ID NAME
A MYNAME
.... etc
i want to return a table of
ID NAME COUNT COUNT2
for the most recent available piece of data, i.e. the january count for A is not included
i know I need to use HAVING, INNER JOIN, and GROUP BY but every iteration I can come up with has an error.
If you only want rows with the date equal to the global maximum date, just use a subquery:
select ID,DATE,COUNT1,COUNT2
from table
where DATE=(select max(DATE) from table);
If you want the maximum date per ID, then you can use a self join:
select ID,MAX_DATE,COUNT1,COUNT2
from(
select ID,max(DATE) as MAX_DATE
from table
group by ID
)a
join(
select ID,DATE,COUNT1,COUNT2
from table
)b
on (a.ID=b.ID and a.MAX_DATE=b.DATE);
Not necessarily. This should also work:
select t1.id, t2.name, t1,count1, t1.count2
from table_1 t1 join table_2 t2 on (t1.id = t2.id)
where not exists (
select 1
from table_1 t3
where t1.id = t3.id
and t1.date < t3.date)
order by 1;
You'll need a correlated subquery:
SELECT Id, Name, Count1, Count2
FROM CountsTable AS T1 INNER JOIN NamesTable ON T1.Id=NamesTable.Id
WHERE CountsTable.Date = (
SELECT Max(Date) From CountsTable AS T2 WHERE T1.Id=T2.Id
)
I've two related tables:
Table1
Id
-----
1
2
3
Table2
Id Feature
--------------
1 Car
1 Moto
1 Camper
2 Moto
2 Scooter
3 Apple
I want to select Ids which have, for example, both 'Car' AND 'Moto'.
So in the example i want to get only Id = 1.
Use the INTERSECT operator:
select id from table2 where feature = 'Car'
intersect
select id from table2 where feature = 'Moto'
This:
WITH features AS
(
SELECT feature
FROM (
VALUES
('Car'),
('Moto')
) q (feature)
)
SELECT *
FROM table1 t1
WHERE NOT EXISTS
(
SELECT feature
FROM features
EXCEPT
SELECT feature
FROM table2 t2
WHERE t2.id = t1.id
)
or this:
SELECT *
FROM table t1
WHERE (
SELECT COUNT(*)
FROM table2 t2
WHERE t2.id = t1.id
AND t2.feature IN ('Car', 'Moto')
) = 2
Which query is more efficient depends on how many records you have in both tables and how many matches there are.
This select does two LEFT OUTER JOINs to table2 (one based on 'Car' and the other based on 'Moto') and makes sure that each JOIN returned a result. The DISTINCT ensures that you get each ID only once.
SELECT DISTINCT t1.id
FROM table2 t2
LEFT OUTER JOIN table2 t2_2 ON t2.id = t2_2.id AND t2_2.feature = 'Moto'
WHERE t2.feature = 'Car'
AND t2_2.id IS NOT NULL
Edit: Removed join to table1 since it really isn't needed.