I suppose this is not so hard but I can not get it.
For example I have table T1:
ID
-----
1000
1001
And I have table T2:
ID GROUP DATE
--------------------------
1000 ADSL 2.2.2012
1000 null 3.2.2012
1000 NOC 4.2.2012
1001 NOC 5.2.2012
1001 null 6.2.2012
1001 TV 7.2.2012
I want to select from T1 only the row that has as GROUP value NOC from T2 but only if NOC group is for the minimum DATE value in T2.
So my result in this case would be only 1001 because for its minimum DATE 5.2.2012 Group is NOC!
I do not want any joins and I can not use default values for IDs (where id=1000 or id=1001) because this is just example of some big table.
Important also is that I can not use t1.id = t2.id because in some application where I am using this I can not write the whole SQL expression but only partial. I can only use id.
I tried something like:
select id
from t1
where
id in (select id from t2
where group = 'NOC'
and date in (select min(date) from t2
where id in (select id from t1)
)
)
But this does not work.
I know it seems little confusing but I really can't use where t1.id = t2.id
Thanks
If T2.ID is a foreign key referencing T1.ID, you don't really need the T1 table, because all the IDs could be obtained from T2 only:
SELECT o.ID
FROM T2 AS o
WHERE EXISTS (
SELECT MIN(i.DATE)
FROM T2 AS i
WHERE i.ID = o.ID
HAVING MIN(i.DATE) = o.DATE
)
WHERE o."GROUP" = 'NOC'
But if you insist on involving T1, you just need to modify the above like this:
SELECT *
FROM T1
WHERE ID IN (
SELECT o.ID
FROM T2 AS o
WHERE o."GROUP" = 'NOC'
AND EXISTS (
SELECT MIN(i.DATE)
FROM T2 AS i
WHERE i.ID = o.ID
HAVING MIN(i.DATE) = o.DATE
)
)
Can you do this in multiple steps?
First of all, to get the minimum date per id, you would need:
select id, peoplegroup, min(date)
from t2
group by id
That will give you
1000 ADSL 2.2.2012
1001 NOC 5.2.2012
Call this table t3.
Then do
select id
from t3
where id in (
select id from t1
)
Try this:
select id from t1 where id in
(select id from t2 where group = 'NOC' and date =
(select min(date) from t2 where id = t1.id))
Related
I have a table like below:
Query:
select t1.*
from TABLE2 as t1
left join TABLE2 as t2 on t1.itemcode = t2.itemcode
and t1.warehouseid = '576'
and t1.flag = 'Y'
and t2.warehouseid = '276'
and t2.flag = 'Y';
I have the above query and understand this is not perfect.
For an itemcode, if these conditions are met (t1.warehouseid='576' and t1.flag='Y' and t2.warehouseid='276' and t2.flag='Y') I want to retrieve that from t1.
Also, If there is no entry for an itemcode in t2 (Ex: 456 is not available for warehouseid 276), that also I want to retrieve from t1.
Expecting the following output,
123 576 Y
456 576 Y
What is the correct query for this?
Edit:
To make the post more clear,
Warehouse id 576 is the main element.
For an itemcode, present in both warehouse id (576 , 276) with the flags being same ('Y') , I want to retrieve.
And If the itemcode is not in the other warehouse (276), that also I want to retrieve
For an itemcode, present in both warehouse id (576 , 276) with different flags ('Y' , 'N') , I don't want that.
interpret directly from your 2 conditions in WHERE clause
select *
from TABLE2 t
where warehouseid = 576
and (
exists -- condition 1
(
select *
from TABLE2 x
where x.itemcode = t.itemcode
and x.warehouseid = 276
and x.flag = 'Y'
)
or not exists -- condition 2
(
select *
from TABLE2 x
where x.itemcode = t.itemcode
and x.warehouseid = 276
)
)
Hope this will work for you
select t1.* from TABLE2 as t1
left join TABLE2 as t2
on t1.itemcode=t2.itemcode and t2.warehouseid='276' and t2.flag='Y';
where
t1.warehouseid='576' and t1.flag='Y'
There is another approach using row_number()
with cte as
(select t1.*,
row_number() over(partition by itemcode order by warehouseid desc
) rn
from TABLE2 t1
where not exists ( select 1 from TABLE2 t2 where t1.itemcode=t2.itemcode
and t2.flag='N'
) and t1.warehouseid=576
) select * from cte where rn=1
So say we have rows
ID | Date
1 1/20
2 1/20
1 1/21
7 1/21
4 1/22
5 1/22
So say I only want to see an ID that appeared in BOTH 1/20 and 1/21.
This should only give me ID 1 since that is the only rows that appears in 1/20 and 1/21. What s the simplest way to achieve this?
I tried doing this:
Select ID, [date]
FROM t1
INNER JOIN (
SELECT ID, Count(*) countRow
FROM t1
Where [date] in(1/20, 1/21)
GROUP BY ID
having count(DISTINCT [Date]) > 1
) aa on t1.id = aa.id
I feel like there's a simple way to achieve this. Any thoughts?
The way you have now is pretty simple. An alternative using exists():
select
t.id
, t.date
from t
where t.date in (1/20, 1/21)
and exists (
select 1
from t as i
where i.id = t.id
and i.date <> t.date
and i.date in (1/20, 1/21)
)
One method uses group by and having:
select id
from t1
where date in ('1/20', '1/21')
group by id
having count(distinct date) = 2;
Of course, if date is really stored as a date, you should fix the format for the date constant to by YYYY-MM-DD.
SELECT ID FROM T1 WHERE Date = '1/20' AND EXISTS (
SELECT ID FROM T1 AS T2 WHERE T2.Date = '1/21' AND
T1.ID = T2.ID)
Not sure it is better
The way you are doing it is pretty standard
Not sure why you need to list the date when that is you where condition
If ID, date is unique then you can use count(*)
Select ID, [date]
FROM t1
INNER JOIN ( SELECT ID
FROM t1
Where [date] = 1/20
intersection
SELECT ID
FROM t1
Where [date] = 1/21
) aa
on t1.id = aa.id
Select ID, [date]
FROM t1
INNER JOIN ( SELECT ID
FROM t1 t1a
join t1 t1b
on t1a.ID = t1b.ID
and t1a.[date] = 1/20
and t1b.[date] = 1/21
) aa
on t1.id = aa.id
If id, value is unique
select id, value
from (select id, value
, count(*) over (partition by id order by value) as cnt
from t
where value in ('a', 'b')
) td
where cnt = 2
order by id, value
this is my table layout simplified:
table1: pID (pkey), data
table2: rowID (pkey), pID (fkey), data, date
I want to select some rows from table1 joining one row from table2 per pID for the most recent date for that pID.
I currently do this with the following query:
SELECT * FROM table1 as a
LEFT JOIN table2 AS b ON b.rowID = (SELECT TOP(1) rowID FROM table2 WHERE pID = a.pID ORDER BY date DESC)
This way of working is slow, probabaly because it has to do a subquery on each row of table 1. Is there a way to improve performance on this or do it another way?
You can try something on these lines, use the subquery to get the latest based on the date field (grouping by the pID), then join that with the first table, this way the subquery would not have not have to be executed for each row of Table1 and will result in better performance:
Select *
FROM Table1 a
INNER JOIN
(
SELECT pID, Max(Date) FROM Table2
GROUP BY pID
) b
ON a.pID = b.pID
I have provided the sample SQL for one column using the group by, in case you need additional columns, add them to the GROUP BY clause. Hope this helps.
use the below code, and note that i added the order by Date desc to get the most resent data
select *
from table1 a
inner join table2 b on a.pID=b.pID
where b.rowID in(select top(1) from table2 t where t.pID=a.pID order by Date desc)
I am using the code below in a similar scenaro (I transcripted it to your example)
SELECT b.*
FROM table1 AS a
left outer join (
SELECT a.*
FROM table2 a
inner join (
SELECT a.pID, max(date) as date
FROM table2
WHERE date <= <max_date>
group by pID
) b ON a.pID = b.pID AND a.date = b.date
) b ON a.pID = b.pID
) b on a.pID = b.pID
The only problem with this aproach is that you have to make sure the date's don't reapet for the pID's
You can do this with the row_number() function and a subquery:
SELECT t1.*
FROM table1 t1 LEFT JOIN
(select t2.*, row_number() over (partition by pId order by rowId desc) as seqnum
from table2 t2
) t2
on t1.pId = t2.pId and t2.seqnum = 1;
Use the ROW_NUMBER() function to get a column saying which id of each row in table 2 is the first (As partitioned by the pID, and ordered by the rowDate descending)
Example:
WITH cte AS
(
SELECT
rowID AS t2RowId,
ROW_NUMBER OVER (PARTITION BY pID ORDER BY rowDate DESC) AS rowNum
FROM table2 t2
) -- gets the t2RowIds + a column which says which is the latest for each pID
SELECT t1.*, t2.*
FROM table1 t1
LEFT JOIN
(
table2 t2
JOIN cte ON t2.rowID = cte.t2RowId AND cte.rowNum = 1
) ON t1.pID = t2.pID
This is guaranteed to only return 1 item from table2 per pID, even if multiple items have the same date. You should of course ensure that the date column is indexed in table 2 for quick performance (ideally an index that also covers the PrimaryID of table2)
I have my MAIN table T1 from which I am doing select of many fields:
ID
1000
I have table T2:
ID SERVICE
1000 IPTV
1000 VOIP
I have table T3:
ID DEVICE
1000 MODEM
1000 ROUTER
1000 DVC
I want to JOIN T1 with T2 or T3 which can but also and might not have values at all !!!!
When they have values I want to have in SELECT number of records of maximum number of records from T2 or T3. So in this case T3 has 3 records which is maximum and I want 3 records in SELECT. (in case that T2 has 3 records that would be maximum in case that T3 has 2 records)
But in my SELECT statement I am having 5 records which I do not want. What is the correct expression for that? My below query returns 5 records (I want 3)
select t1.id,t2.service,t3.device
from t1
left outer join T2 on t1.id=t2.id
left outer join T3 on t1.id=t3.id
SELECT
t1.id
, t2.service
, t3.device
FROM
t1
LEFT JOIN
( SELECT
ROW_NUMBER() OVER (PARTITION BY id ORDER BY service) AS rn
, id
, service
FROM
t2
) AS t2
FULL JOIN
( SELECT
ROW_NUMBER() OVER (PARTITION BY id ORDER BY device) AS rn
, id
, device
FROM
t3
) AS t3
ON t3.id = t2.id
AND t3.rn = t2.rn
ON COALESCE(t2.id, t3.id) = t1.id ;
this requirement doesn't sound right, but the following should work
SELECT T1.*, z2.ID, z2.SERVICE FROM
(
SELECT ID, CASE WHEN SUM(INDICATOR) >=0 THEN 1 ELSE -1 END AS INDICATOR FROM
(
SELECT ID, SERVICE, 1 AS INDICATOR FROM t2
UNION ALL
SELECT ID , DEVICE AS SERVICE , -1 AS INDICATOR FROM t3
) z
GROUP BY ID
) z1
INNER JOIN
(
SELECT ID, SERVICE, 1 AS INDICATOR FROM t2
UNION ALL
SELECT ID , DEVICE AS SERVICE, -1 AS INDICATOR FROM t3
) z2
ON z1.ID = z2.ID AND z1.INDICATOR = z2.INDICATOR
RIGHT JOIN T1 ON T1.ID = Z2.ID
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
)