Trying to look up records based on a join - sql

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;

Related

SQL aggregate and filter functions

Consider following table:
Number | Value
1 a
1 b
1 a
2 a
2 a
3 c
4 a
5 d
5 a
I want to choose every row, where the value for one number is the same, so my result should be:
Number | Value
2 a
3 c
4 a
I manage to get the right numbers by using nested
SQL-Statements like below. I am wondering if there is a simpler solution for my problem.
SELECT
a.n,
COUNT(n)
FROM
(
SELECT number n , value k
FROM testtable
GROUP BY number, value
) a
GROUP BY n
HAVING COUNT(n) = 1
You can try this
SELECT NUMBER,MAX(VALUE) AS VALUE FROM TESTTABLE
GROUP BY NUMBER
HAVING MAX(VALUE)=MIN(VALUE)
You can try also this:
SELECT DISTINCT t.number, t.value
FROM testtable t
LEFT JOIN testtable t_other
ON t.number = t_other.number AND t.value <> t_other.value
WHERE t_other.number IS NULL
Another alternative using exists.
select distinct num, val from testtable a
where not exists (
select 1 from testtable b
where a.num = b.num
and a.val <> b.val
)
http://sqlfiddle.com/#!9/dd080dd/5

SQL to return if value is double

I have a question on how to validate if a row's doubled when other columns meet criteria.
The table looks looks like this:
Type Name ID Am
O Name1 1234 1
O Name1 1235 1
O Name1 4569 2
X Name2 1234 1
X Name2 4569 2
C name3 1234 1
For type O, I have under Name1, 2 ID's for the same Am = 1.
I'd like to to do a query that would check if multiples IDs can be found under same type & name & am values and return if >1, but ignore the rest of the types.
Thank you!
Try this
select type, name, am
from table
group by type, name, am
having count(*)>1
most dbms support row_number,so you can use this
select * from
(
select *, row_number() over(partition by Type,Name,Am order by ID) as rn
from t
) t1 where t1.rn>1
Are you trying to check if a combination of type/name has more than one am value?
If so:
select type, name
from t
group by type, name
having min(am) <> max(am);
I would use NOT EXISTS :
SELECT t.*
FROM table t
WHERE EXISTS (SELECT 1
FROM table t1
WHERE t1.Type = t.Type AND t1.Name = t.Name AND t1.Am = t.Am AND t1.ID <> t.ID
);

Select rows having the same features than others

I've the following table with 3 columns: Id, FeatureName and Value:
Id FeatureName Value
-- ----------- -----
1 AAA 10
1 ABB 12
1 BBB 12
2 AAA 15
2 ABB 12
2 ACD 7
3 AAA 10
3 ABB 12
3 CCC 12
.............
Each Id has different features and each Feature has a value for that Id.
I need to write a query which gives me the Ids that have exactly the same features and values than a given one, but only taking into account those whose name starts with 'A'. For example, in the top table, I can use that query to search for all the Ids that have the same features. For example, features with values where Id=1 would result Id=3 with same features starting with 'A' and same values for these features.
I found a couple of different ways to do this, but all of them go very slow when the table has lots of rows (more than hundred of thousands)
The way I obtain the best performance is using the next query:
select a2.Id
from (select a.FeatureName, a.Value
from Table1 a
where a.Id = 1) a1,
(select a.Id, a.FeatureName, a.Value
from Table1 a
where a.FeatureName like 'A%') a2
where a1.FeatureName = a2.FeatureName
and a1.value = a2.value
group by a2.Id
having count(*) = 2
intersect
select a.Id
from Table1 a
where a.FeatureName like 'A%'
group by a.Id
having count(*)= 2
where #nFeatures is the number of features starting by 'A' in Id=1. I counted them before calling this query. I make the intersection to avoid results that have the same parameters than Id=1 but also some others whose name starts with 'A'.
I think that the slowest part is the second subquery:
select a.Id, a.FeaureName, a.Value
from MyTable a
where a.FeatureName = 'A%'
but I don't know how to make it faster. Maybe I will have to play with the indexes.
Any idea of how could I write a fast query for this purpose?
So you want all rows where the combination of FeatureName and Value is not unique? You can use EXISTS:
SELECT t.*
FROM dbo.Table1 t
WHERE t.FeatureName LIKE 'A%'
AND EXISTS(SELECT 1 FROM dbo.Table1 t2
WHERE t.Id <> t2.ID
AND t.FeatureName = t2.FeatureName
AND t.Value = t2.Value)
Demo
how could I write a fast query for this purpose?
If it's not fast enough create an index on FeatureName + Value.
I tried to eliminate the join with MyTable again to select the data for the ID's that have matching FeatureName and Value values. Here's the query:
with joined_set as
(
SELECT
mt1.*, mt2.id as mt2_id, mt2.featurename as mt2_FeatureName, mt2.value as mt2_value
from
(
select *
from mytable
where featurename like 'A%'
) mt1
left join
(
select *
from mytable
where featurename like 'A%'
) mt2
on mt2.id <> mt1.id and mt2.FeatureName = mt1.featurename and mt2.value = mt1.value
)
select distinct id
from joined_set
where id not in
(select id
from joined_set
group by id
having SUM(
CASE
WHEN mt2_id is null THEN 1
ELSE 0
END
) <> 0
);
Here is the SQL Fiddle demo. It has an extra condition in the inline view mt2, to perform this search only for id = 1.
I'm a little dense this morning, I'm not sure if you wanted just the ID's or...
Here's my take on it...
You could probably move the where FeatureName like 'A%' into the inner query to filter the data on the initial table scan.
with dupFeatures (FeatureName, Value, dupCount)
as
(
select FeatureName, Value, count(*) as dupCount from MyTable
group by FeatureName, Value
having count(*) > 1
)
select MyTable.Id, dupFeatures.FeatureName,dupFeatures.Value
from dupFeatures
join MyTable on (MyTable.FeatureName = dupFeatures.FeatureName and
MyTable.Value = dupFeatures.Value )
where dupFeatures.FeatureName like 'A%'
order by FeatureName, Value, Id
A general solution is
With Rows As (
select id
, FeatureName
, Value
, rows = Count(id) OVER (PARTITION BY id)
FROM test
WHERE FeatureName LIKE 'A%')
SELECT a.id aID, b.id bID
FROM Rows a
INNER JOIN Rows b ON a.id < b.id and a.FeatureName = b.FeatureName
and a.rows = b.rows
GROUP BY a.id, b.id
ORDER BY a.id, b.id
to limit the solution to a group just add a WHERE condition on the main query for a.ID. The CTE is needed to get the correct number of rows for each id
SQLFiddle demo, in the demo I changed little the test data to have a another couple of ID with only one of the FeatureName of 1 and 3

SQL: selecting unique values based on conditions

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.

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
)