SQL: selecting unique values based on conditions - sql

I have a table containing 5 columns. The first column contains an ID, two columns contain parameters for those IDs with the values 0 or 1, a third column contains a parameter which I need as output, the last column contains a date. The same ID can appear in several rows with different parameters:
ID parameter1 parameter2 parameter3 date
001 0 1 A 01.01.2010
001 0 1 B 02.01.2010
001 1 0 C 01.01.2010
001 1 1 D 01.01.2010
002 0 1 A 01.01.2010
For each unique ID I want to return the value in parameter3, the decision from which row to return this value is based on the values in parameter1 and parameter2 and the date:
If there is a row with both parameters being 0, I want the value in this row.
If there is no such row, I want the value from the row where parameter1 is 0 and parameter2 is 1,
If there is no such row, I want the row where parameter1 is 1 and parameter2 is 0.
Finally, if there is no such row, I want the value from the row with both parameters being 1.
If there is more than one row matching the required conditions, I want the row with the most recent date.
e.g., for the table above, for the ID 001 I would want the second row with the value B in parameter3.
What would be the most effective / fastest way to accomplish this? I tried two approaches so far:
the first one was to select all distinct IDs and then loop through the distinct IDs, using a select statement with the ID in the where clause and then loop through all the rows matching the ID while storing the necessary values in variables.:
foreach
select distinct ID into i_ID from table1
foreach
let o_case = 5
select case
when parameter1 = 0 and parameter2 = 0 then 1
when parameter1 = 0 and parameter2 = 1 then 2
when parameter1 = 1 and parameter2 = 0 then 3
when parameter1 = 1 and parameter2 = 1 then 4
end, parameter3, date
into i_case, i_p3, i_date
from table3
where table3.ID = i_ID
if i_case < o_case
then let o_p3, o_case, o_date = i_p3, i_case, i_date;
else ( if i_case = o_case and i_date > o_date
then let o_p3, o_date = i_p3, i_date;
end if;
end if;
end foreach;
insert into table_output values(i_ID; o_p3);
end foreach;
The second approach was to left join the table four times with itself on the ID and apply the different combinations of the parameter1 & parameter2 as described above in the left joins, then selecting the output via nested nvl clauses:
select ID,
nvl(t1.parameter3,
nvl(t2.parameter3,
nvl(t3.parameter3,
nvl(t4.parameter3)))) parameter3
from table1 t0
left join table1 t1
on t0.ID = t1.ID and t1.parameter1 = 0 and t1.parameter2 = 0
and t1.date = (select max(date) from table1 t1a where t1a.ID = t1.ID)
left join table1 t2
on t0.ID = t2.ID and t2.parameter1 = 0 and t2.parameter2 = 1
and t2.date = (select max(date) from table1 t2a where t2a.ID = t1.ID)
left join table1 t3
on t0.ID = t3.ID and t3.parameter1 = 1 and t3.parameter2 = 0
and t3.date = (select max(date) from table1 t3a where t3a.ID = t3.ID)
left join table1 t4
on t0.ID = t4.ID and t4.parameter1 = 1 and t4.parameter2 = 1
and t4.date = (select max(date) from table1 t4a where t4a.ID = t4.ID)
Both approaches basically worked, however, as the table is really long, they were much too slow. What would you recommend?
PS: DBMS is IBM Informix 10, this unfortunately restricts the range of available functions a lot.

I'm not sure if this is what you wanted, but this could work:
SELECT id, parameter3
FROM (
SELECT id, parameter3, RANK() OVER (
PARTITION BY id, parameter3
ORDER BY parameter1 ASC, parameter2 ASC, date DESC
)
FROM tab
) AS x
WHERE x.rank = 1;

ID parameter1 parameter2 parameter3 date
001 0 1 A 01.01.2010
001 0 1 B 02.01.2010
both of the above rows having same ID, paramaeter1, parameter2 but different paraameter3, it can create trouble for you.

Related

DB2 SQL Result Set without Duplicates

I am trying to adjust this SQL syntax to only show one row if it has a dash number in the field or field is empty.
Select Distinct TRIM(TRANSLATE(itnbr,' ','F')),
Case When t3.dashonly Is NULL Then '' Else t3.dashonly End As dashonly
From amflib1.itmrva t1
Join webprddt1.drawmext17 t2 On t2.afctdwg = t1.uu25
Left Join webprddt1.wqmssoadn t3 On t3.itemno = t1.itnbr
Where t2.recseq = '0060' Order By 1
As is the resultset is:
00001 DASHONLY
--------------- ---------------
41031052-1
41031052-1 -1
41031052-10
41031052-11 -11
41031052-11
41031052-12
41031052-12 -12
41031052-13
41031052-14
41031052-15
41031052-17
Desired resultset:
00001 DASHONLY
--------------- ---------------
41031052-1 -1
41031052-10
41031052-11 -11
41031052-12 -12
41031052-13
41031052-14
41031052-15
41031052-17
Thought I don't have test data to test your query, the query below should work.
You can use ROW_NUMBER() to sort the rows in each subgroup according to a sorting criteria, and then just pick the first one per group.
select *
from (
select
TRIM(TRANSLATE(itnbr,' ','F')),
case when t3.dashonly is null then '' else t3.dashonly end As dashonly,
row_number() over(partition by TRIM(TRANSLATE(itnbr,' ','F'))
order by case when t3.dashonly is null then 0 else 1 end) as rn
from amflib1.itmrva t1
join webprddt1.drawmext17 t2 on t2.afctdwg = t1.uu25
left join webprddt1.wqmssoadn t3 on t3.itemno = t1.itnbr
where t2.recseq = '0060'
) x
where rn = 1
order by 1

Trying to look up records based on a join

I'm trying to work on a stored procedure that is somewhat tricky, let's say I have Table_1 with this data:
Num1 Name1 Code1 Desc
-------------------------------------------
123B Apple 10 Text1
123B Apple 11 Text1
123C Google 20 Text2
I also have a lookup table that looks like this:
Tbl_LookUp
Num1 Code1
-------------------
123B 10
123C 25
So what I am trying to do in this scenario is:
Select data from Table_1 WHERE:
There is a match between Table_1 and Tbl_Lookup on Num1
and
If there is a more than 1 record for a particular Num1 in Table_1, then only return the row where Table_1.Code1=Tbl_Lookup.Code1
Otherwise, if there is only 1 record for a particular Num1 in Table_1, then even if the Table_1.Code1 = Tbl_Lookup.Code1 does not work, still return the record.
Desired end result:
Num1 Name1 Code1 Desc
--------------------------------------------
123B Apple 10 Text1
123C Google 20 Text2
123B is returned because there are multiple records for this Num1. One of them has the Code1 that corresponds to Tbl_Lookup.Code1
123C is returned, because although the Code1 does not match Tbl_Lookup, there is only one record, so in that case join doesn't matter, and we still want to return it.
Any help is greatly appreciated.
Not sure if there is a better way to do this. But this should give you want you are looking for
select t.*
from table1 t
join Tbl_LookUp l on l.Num1 = t.Num1
where t.code1 = l.code1
or exists ( select count(1) from table1 i
where i.Num1= t.Num1
group by Num1
having count(Num1) = 1 )
One way is
select t.Num1, t.Name1, t.Code1, t.Desc
from (
select Num1, Name1, Code1, Desc,
count(code1) over(partition by Num1) cnt
from Table_1 ) t
join Tbl_Lookup tl on t.Num1 = tl.Num1
and (t.cnt = 1 or t.Code1 = tl.Code1)
This is a great place to use apply:
select t1.*
from tbl_lookup l cross apply
(select top (1) t1.*
from table1 t1
where t1.num1 = l.num1
order by (case when t.code = l.code1 then 1 else 2 end)
);
Yet another way to obtain the desired results - identify exact lookup matches with exists and count occurences of num1, then allow any with a count of 1 or only matches on both columns where more than 1:
select num1, name1, code1, [desc]
from (
select * , case when exists (select * from [lookup] l where l.num1 = t.num1 and l.code1 = t.code1) then 1 end lmatch, Count(*) over (partition by num1) cnt
from t1 t
where exists (select * from [lookup] l where l.num1 = t.num1)
)x
where lmatch = 1 and cnt > 1 or cnt = 1;

Update column in table depending on table data

I am working on a table on SQL where I need to fill in a new column depending on the value of 2 other columns in the table.
The rules are:
- New column = 1 if Row id = 1 and the group id for that row has more rows with the same group id (See pic)
- New column = 2 if Row id >= 2
- Anything else will make the new column 0
Table
This is my query to update the new column which works:
UPDATE t1 SET t1.New_Column = CASE WHEN t1.RowID >= 2 THEN 2
ELSE CASE WHEN t1.RowID = 1 and (SELECT count(*) FROM dbo.__test1 as t2 WHERE t2.GroupID = t1.GroupID) > 1
THEN 1 ELSE 0 END END from dbo.__test1 as t1
The end table result(Correct):
I want to know if there is a better and more efficient way of updating the new column as I feel calling the table within the select to count the number of group id's doesn't seem right?
Thanks
It will be faster to get the counts at the table level instead of row.
Removed one level of your CASE expression too - that probably won't change anything but it's a little cleaner to my eyes.
UPDATE t
SET t.NewColumn = CASE WHEN t2.RowID >=2 THEN 2
WHEN t2.RowID = 1 AND cnt > 1 THEN 1
ELSE 0
END
FROM dbo.__test1 t
JOIN (SELECT GroupID, COUNT(*) cnt
FROM dbo.__test1
GROUP BY GroupID) t2 on t.GroupID = t2.GroupID

results of a sub table in the top level query

Not sure how to title this so please feel free to retitle.
I have two tables with a one to many relationship.
Table1
|ID|NAME|...|
Table2
|ID|Table1_ID|StartDate|EndDate|
I am trying to write a query that given a date will return the following
|TABLE1.ID|TABLE1.NAME|are any rows of table 2 in date|
I have a one to many between table 1 and table 2. I want to pass in a date to the query. If any of the many relationships in table 2 have a start date < passed in date and an end date > passed in date or end date is null then I want column 3 of result to be true. Otherwide I want it to be false.
Consider the example
|ID|NAME|...|
| 1|APPLE| ...|
| 2|PEAR| ...|
Table2
|ID|Table1_ID|StartDate|EndDate|
|1|1|01-01-2014|null|
|2|1|01-01-2014|01-02-2014|
|3|2|01-01-2014|01-02-2014|
if I pass in 01-01-2014 then I expect two rows with IDs 1 and 2 and both to be true (all rows match)
if I pass in 01-03-2014 then I expect two rows with ID 1 true (match on first row) and ID 2 to be false (because third row is outside of this date)
I am trying to do this in SQL to eventually convert to JPA. If there are any JPA functions that can do this then that would be good to know. Else I'll do a native query
Any pointers would be great!
Thanks
This should give you what you want:
select x.*, 'PASS' as checker
from table1 x
where exists
(select 'x'
from table2 y
where y.table1_id = x.table1_id
and y.startdate <= '01-01-2014'
and (y.enddate >= '01-01-2014' or y.enddate is null))
union all
select x.*, 'FAIL' as checker
from table1 x
where not exists
(select 'x'
from table2 y
where y.table1_id = x.table1_id
and y.startdate <= '01-01-2014'
and (y.enddate >= '01-01-2014' or y.enddate is null))
I don't know if I understand your question.
So, please, be patient... ;)
Try something like this:
select t1.id, t1.name,
case when t2.Table1_ID is null
then 'false'
else 'true' end as boolean_value
from Table1 t1,
(select distinct Table1_ID
from Table2
where yourdate >= StartDate
and (yourdate <= EndDate or EndDate is null) t2
where t1.id = t2.id (+);

Exclude rows if column values are equal of same table

![TABLE][1]
Hello All,
I have a table with above records where you can 2 entries for each N_ID. I would like to get the records from this only if below condition is satisfied.
Say for example
Status column value is 1 & 2 for N_ID =2 and 2 & 1 for N_ID=5 which means status value is different(i.e Both 1 & 2).
But if you see N_ID=3, Status column has 1 & 1 which is same.
So i want the records excluding N_ID which has same status value(i.e Which has 1 & 1 or 2 & 2 and so on).
In above case, i want only the records with N_ID=2,5.
thanks
You can use EXISTS
SELECT * FROM dbo.TableName t1
WHERE EXISTS(
SELECT 1 FROM dbo.TableName t2
WHERE t1.N_ID = t2.N_ID
AND t1.Status <> t2.Status
)
You can exclude the rows where you have more than one occurrence of the same status per ID
SELECT *
FROM TABLENAME tb
WHERE tb.N_ID NOT IN (
SELECT tb.N_ID
FROM TABLENAME tb
GROUP BY tb.N_ID, tb.CONFIG_TYPE, tb.STATUS
HAVING COUNT(*) > 1)
Try option with EXISTS() and check COUNT(*)
SELECT *
FROM dbo.test16 t
WHERE t.Config_Type != 2 AND EXISTS (
SELECT 1
FROM dbo.test16 t2
WHERE t.Networkelemenid = t2.Networkelemenid
GROUP BY t2.Networkelemenid, t2.Config_Type
HAVING COUNT(DISTINCT t2.Status) > 1
)
This script grouped data on t2.Config_Type. HAVING COUNT(DISTINCT t2.Status) specifies that only unique rows can appear in the result set.(e.g. 1,2 = 2; 1,1 or 2,2 = 1)
For second condition you need this script
SELECT *
FROM dbo.test41 t
WHERE t.Config_Type != 2 AND EXISTS (
SELECT 1
FROM dbo.test41 t2
WHERE t.Networkelemenid = t2.Networkelemenid
GROUP BY t2.Networkelemenid, t2.Config_Type, t2.Status
HAVING COUNT(t2.Status) > 1
)