Where should i put in DISTINCT? - sql

I'm trying to only fetch unique result of several duplicates in this little complex query:
$sql = "SELECT t1.*, t2.floor_id
FROM dbo.IMP_ELEMENT AS t1
INNER JOIN dbo.IMP_MODEL_GEOMETRY t2 ON CONCAT(t1.Project, '_', t1.element_mark) = CONCAT(t2.Project, '_', t2.element_mark)
WHERE CONCAT(t2.Project, '-', t2.floor_id) LIKE '%$objNr%'";
I expect to only receive unique result from t2.element_mark.
So where should I put in DISTINCT? or is there another way to achieve this?
In t1, Element_mark is unique, but in t2, Element_mark can have duplicates.
So from t1 I like to receive all data. But from t2 I want DISTINCT element_mark. From t2 i only display floor_id, But I need to use Element_mark and Project to match t1 & t2 rows.
EDIT
It doesn't matter which of the duplicates in t2.element_mark I display. t2.floor_id is the same on all duplicates.
**
t1
----------------------------------------------
id project element_mark type ...
0 1 1 A ...
1 1 2 A ...
2 1 3 A ...
t2
----------------------------------------------
id project element_mark flood_id ...
0 1 1 1 ...
1 1 1 1 ...
2 1 2 1 ...
3 1 3 2 ...
As seen in t1, all element_mark is unique. But in t2, element_mark can be seen twice or more.
What I want is to select * from t1.
The id like to select DISTINCT element_mark, floor_id FROM t2 WHERE CONCAT(t1.project, '', t1.element_mark) = CONCAT(t2.project, '', t2.element_mark)

try like below using subquery
SELECT t1.*, t2.floor_id
FROM dbo.IMP_ELEMENT AS t1
INNER JOIN (select distinct project,element_mark,flood_id from dbo.IMP_MODEL_GEOMETRY) t2 ON CONCAT(t1.Project, '_', t1.element_mark) = CONCAT(t2.Project, '_', t2.element_mark)
WHERE CONCAT(t2.Project, '-', t2.floor_id) LIKE '%$objNr%'

If as you say
t2.floor_id is the same on all duplicates.
then your query is fine and you can add DISTINCT in your select
$sql = "SELECT DISTINCT t1.*, t2.floor_id
FROM dbo.IMP_ELEMENT AS t1
INNER JOIN dbo.IMP_MODEL_GEOMETRY t2 ON CONCAT(t1.Project, '_', t1.element_mark) = CONCAT(t2.Project, '_', t2.element_mark)
WHERE CONCAT(t2.Project, '-', t2.floor_id) LIKE '%$objNr%'";
UPDATE:
Your query returns
----------------------------------------------
id project element_mark type flood_id
0 1 1 A 1
0 1 1 A 1
1 1 2 A 1
2 1 3 A 2
Adding Distinct returns
----------------------------------------------
id project element_mark type flood_id
0 1 1 A 1
1 1 2 A 1
2 1 3 A 2

Related

Joining tables without nulls

I'm not sure how to explain what I need but here's the data first:
Table 1
District
-1
3
2
1
3
Table 2
ID ID_Name
1 Main 1
2 Main 2
3 Main 3
How do I join the tables so that it looks like this?
District
-1
Main 3
Main 2
Main 1
Main 3
I'm assuming the second column is named Name for this, but you can do it with a COALESCE and a LEFT JOIN:
Select Coalesce(T2.Name, Str(T1.District)) As District
From Table1 T1
Left Join Table2 T2 On T1.District = T2.Id
assuming table 2 have
Table 2
ID col2
1 Main 1
2 Main 2
3 Main 3
you could use a left join
select table1.Distric, table2.col2
from table1
left join table2 on table1.dictrict = t2.ID
order by table2 col2
You can use left join:
Select coalesce(t2.col, t1.District) from table1 t1
left join table2 t2 on t1.District = t2.Id

How to get Oracle to return unique results in a one to many relationship tables with a left join

I have a three tables
Table 1
Id Department
1 A
2 B
3 C
4 D
Table 2
Id DepartId Name
1 1 ABC
2 1 DEF
3 1 ASD
4 2 FGH
5 2 HJK
6 3 ZXC
Table 3
Id Depart Area
1 A pp
2 B
3 C nn
4 D oo
I need the result
Id Depart Name Area
1 A ABC pp
2 B FGH Null
3 C ZXC nn
4 D NULL oo
I need one matching entry from table 2 and table 3 to corresponding entry in the table 1
Do a left join to also get t1 rows without any reference in the t2 table. GROUP BY to get only 1 row per Department.
select t1.id, t1.Department, min(t2.Name)
from t1
left join t2 on t1.id = t2.DepartId
group by t1.id, t1.Department
I think I would do this with a correlated subquery:
select t1.*,
(select t2.name
from t2
where t1.id = t2.DepartId and rownum = 1
) as t2name
from t1;
This saves the overhead of an aggregation. An index on t2(DepartId, name) is optimal for this query.
by the way not the answer to your specific question but if instead of just one you want all the names you can use listagg
SELECT t1.id,
department,
LISTAGG (name, ',') WITHIN GROUP (ORDER BY name) names
FROM t1, t2
WHERE t1.id = t2.departId(+)
GROUP BY t1.id, department
ORDER BY 1
ID Department Names
1 A ABC,ASD,DEF
2 B FGH, HJK
3 C ZXC
4 D

SQL (oracle) Update some records in table using values in another table

I have to tables :
Table1
--------------------------------
ID VAL1 DATE1
--------------------------------
1 1 20/03/2015
2 null null
3 1 10/01/2015
4 0 12/02/2015
5 null null
Table2
--------------------------------
ID VAL2 DATE1
--------------------------------
1 N 02/06/2015
1 N 01/08/2015
2 null null
3 O 05/04/2016
3 O 02/02/2015
4 O 01/07/2015
5 O 03/02/2015
5 N 10/01/2014
5 O 12/04/2015
I want to update :
column VAL1 (of Table1) with '0', if VAL2 (of Table2) is equal to 'O'
column DATE1 (of Table1) with the earliest DATE2 (of Table2) for each ID (here my problem)
(This two tables are not so simple, it's just for illustration, they can be joined with the ID column).
Here my code :
UPDATE Table1 t1
SET t1.VAL1 = '0',
t1.DATE1 = (select min(t2.DATE2) --To take the first DATE for each ID where VAL2='O' (not working fine)
FROM Table2 t2, Table1 t1
WHERE trim(t2.ID) = trim(t1.ID)
AND VAL2='O')
WHERE EXISTS (SELECT NULL
FROM Table2 t2
WHERE trim(t2.ID) = trim(t1.ID)
AND t2.Table2 = 'O')
AND VAL1<>'0'; --(for doing the update only if VAL1 not already equal to 0)
The expected result is :
Table1
--------------------------------
ID VAL1 DATE1
--------------------------------
1 1 20/03/2015
2 null null
3 0 02/02/2015
4 0 01/07/2015
5 0 10/01/2014
The result I get is :
Table1
--------------------------------
ID VAL1 DATE1
--------------------------------
1 1 20/03/2015
2 null null
3 0 10/01/2014
4 0 10/01/2014
5 0 10/01/2014
My problem is that the DATE1 is always updated with the same date, regardless of the ID.
You shouldn't have a second reference to table1 in the first subquery; that is losing the correlation between the subquery and the outer query. If you run the subquery on its own it will always find the lowest date in table2 for any ID that has val2='O' in table1, which is 10/01/2014. (Except your sample data isn't consistent; that's actually N so won't be considered - your current and expected results don't match the data you showed, but you said it isn't real). Every row eligible to be updated runs that same subquery and gets that same value.
You need to maintain the correlation between the outer query and the subquery, so the subquery should use the outer table1 for its join, just like the second subquery already does:
UPDATE Table1 t1
SET t1.VAL1 = '0',
t1.DATE1 = (select min(t2.DATE2)
FROM Table2 t2
WHERE trim(t2.ID) = trim(t1.ID)
AND VAL2='O')
WHERE EXISTS (SELECT NULL
FROM Table2 t2
WHERE trim(t2.ID) = trim(t1.ID)
AND t2.Val2 = 'O')
AND VAL1<>'0';
You can use this UPDATE statement.
UPDATE TABLE1 T1
SET T1.VAL1 = '0',
T1.DATE1 = (SELECT MIN(T2.DATE2)
FROM TABLE2 T2
WHERE TRIM(T2.ID) = TRIM(T1.ID)
AND T2.VAL2='O')
WHERE T1.ID IN (SELECT T2.ID FROM TABLE2 T2 WHERE T2.VAL2='O')
Hope it will help you.
MYSQL Solution
Hope this MySql syntax also works with ORACLE.
The issue with the SQL is that it only consider the records with VAL2=='O' when calculating the earliest date. So the last record have the date as shown in table below. Record "5 N 10/01/2014" is not considered.
UPDATE Table1, (SELECT * FROM (SELECT * FROM table2 WHERE VAL2='O' ORDER BY ID, DATE1) X GROUP BY X.ID) T2
SET Table1.DATE1=T2.DATE1, Table1.VAL1=0
WHERE Table1.ID=T2.ID
..
Table1
--------------------------------
ID VAL1 DATE1
--------------------------------
1 1 20/03/2015
2 null null
3 0 02/02/2015
4 0 01/07/2015
5 0 **03/02/2015**
Tested on MySql 5.6.14

Compare multiple Rows Based on another table

Lets say I have following tables:
Table1
ID Number
1 2
2 34
3 1 <---- Input (ID = 3) ==> (Number = 1)
4 6
5 5
*6* 7 <---- Want to find (Number = 6) because match in Table2
7 22
and Table2
Number Code Att1 Att2 Att3
1 1 1 <-----|
1 2 1 2 <-----|
6 2 f 2 |
6 3 4 3 2 |
2 4 6 |---Match
22 5 2 2 2 |
5 2 h 3 b |
7 1 1 <-----|
7 2 1 2 <-----|
7 h 5 r
So here is my Problem:
I want the IDs from Table1 that have all Code and Attributes from Table2 that a given (variable) input ID has. At the end I want to create a stored procedure/function that gives me all IDs meeting that condition.
As an Example:
Input-ID: 3. Would return ID 6 because Number 7 (mapped from ID 6 in Table1) has the rows Number 1 (mapped from ID 3 in Table1) has. It has more but that doesn't matter, its just important it has all rows the input one has.
(I can't find a solution to comparing a set of rows to another set of rows that is not known before.)
Thanks for any help!
Edit:
To make it more understandible, here what I want in words step-by-step.
Map input ID to Number in Table1
Get All Rows from Table2 having Number from Step 1
Get all Number that have the same (can have more) Rows as from Step 2
Get IDs for that Numbers (and return them)
Try something like this. Haven't tested it, but basically you inner join on all of the attributes that need to match. The HAVING clause is a crude check to make sure that it matched all the rows. Edit: Forgot to add the input ID WHERE clause.
SELECT t1b.ID FROM
Table1 t1a
INNER JOIN Table2 t2a ON t1a.Number = t2a.Number
INNER JOIN Table2 t2b ON t2a.Number <> t2b.Number AND t2a.Code = t2b.CODE AND t2a.Att1 = t2b.Att1 AND t2a.Att2 = t2b.Att2 AND t2a.Att3 = t2b.Att3
INNER JOIN Table1 t1b ON t1b.Number = t2b.Number
WHERE t1a.ID = 3
GROUP BY t1b.ID
HAVING COUNT(*) = (SELECT COUNT(*) FROM Table1 WHERE ID = t1a.ID)
select t11.ID as Id_To_Find,t12.ID as Id_Found
from Table1 t11
join (
select t21.Number as Found,t22.Number as ToFind from Table2 t21
left join Table2 t22 on t21.Code = t22.Code
and t21.Att1 = t22.Att1
and t21.Att2 = t22.Att2
and t21.Att3 = t22.Att3
and t21.Number <> t22.Number
group by t21.Number,t22.Number
having COUNT(*) = (select COUNT(*) from Table2 where Number = t22.Number))
as FindMatches
on t11.Number = FindMatches.ToFind
join Table1 t12 on t12.Number = FindMatches.Found
Kind of hard to understand what you're trying to acheive. As i understood from your example, you want to match the Number for the input ID in Table1 with any column (correct?) in Table2.
With input ID=3, the SELECT will return Number=7. In the IN (...)-condition, you can specify whichever columns in Table2 you want to match to Table1.Number.
DECLARE #Input INT = 3 -- Your input
SELECT DISTINCT t1.Number
FROM Table1 t
INNER JOIN Table2 t2 ON t.Number IN (t2.Number, t2.Code, t2.Att1, t2.Att2, t2.Att3)
INNER JOIN Table1 t1 ON t2.Number = t1.Number AND t.ID <> t1.ID
WHERE t.ID = #Input

select data having same id

id idtest result
1 1 2
1 2 1
1 3 2
2 1 2
2 2 1
2 3 1
3 1 1
3 2 2
3 3 1
Would like to get all the rows with the same IDs that matches the condition.
For example: get all the rows with the same id where (idTest=2 and result=1) and (idTest=3 and result=2)
result:
id idtest result
1 1 2
1 2 1
1 3 2
What would be the query???
Thanks!
Do you mean this?
SELECT * FROM table WHERE id = 1 and (result = 1 OR result = 2)
How about his:
SELECT *
FROM table WHERE (idTest = 2 OR idTest = 3) AND (result=1 OR result=2)
ID test res
1 1 2
1 2 1
1 3 2
2 1 1
2 2 2
2 3 2
3 1 1
3 2 2
3 3 1
Sorry. This would be my table. and Would like to get all the rows with the same IDs that matches the condition. For example: get all the rows with the same id where (test=2 and res=1) and (test=3 and res=2)
Result:
ID test res
1 1 2
1 2 1
1 3 2
What would be the query in order to get the three rows ?? Thanks!
You can use EXISTS:
SELECT id, idTest, result
FROM dbo.TableName t
WHERE EXISTS
(
SELECT 1 FROM dbo.TableName t2
WHERE t.id = t2.id
AND(
( t2.idTest=2 AND t2.result=1 )
OR
( t2.idTest=3 AND t2.result=2 )
)
)
Demo
Update: result is different:
id idTest result
1 1 2
1 2 1 <-- satisfies your condition
1 3 2 <-- satisfies your condition
2 1 2
2 2 1 <-- satisfies your condition
2 3 1
So either my understanding was incorrect or your expected result. I have also all ID=2 because the second id-2 row matches the condition.
You seem to want all rows for id's that have rows with that particular combination. What about:
with ids as (
select id
from mytable
where (idTest=2 and result=1) or (idTest=3 and result=2)
group by id
having count(id) = 2
)
select mytable.* from mytable
inner join ids
on ids.id = mytable.id
This gets a list of id's where both conditions apply, and then gets all rows for those id's.
SqlFiddle
SELECT *
FROM table t1
WHERE EXISTS (SELECT 1 FROM table WHERE id = t1.id AND idtest = 2 AND result = 1)
AND EXISTS (SELECT 1 FROM table WHERE id = t1.id AND idtest = 3 AND result = 2)
Just keep adding more AND EXISTS if you need more
Or you can use IN if it makes more sense to you
SELECT *
FROM table
WHERE id IN (SELECT id from table where idtest = 2 and result = 1)
AND id IN (SELECT id from table where idtest = 3 and result = 2)
do you need a method that treats the condition(s) in a generic way, like if they're values in another table? Or do you only need a way to pull results of two independent conditions?
If the latter, then this should work:
SELECT
id
FROM
(SELECT id
FROM tbl
WHERE idTest=2 AND RESULT=1) cond1 INNER JOIN
(SELECT id
FROM tbl
WHERE idTest=3 AND RESULT=2) cond2 ON
cond1.id = cond2.id
otherwise, if your conditions are generic and stored in a table, you'd need something like:
SELECT
id
FROM
(SELECT id
FROM tbl FULL OUTER JOIN conditions c
WHERE c.isUseMe = 1 AND c.SEQ = 1 AND idTest=c.idTestVal AND result=c.resultVal) cond1 INNER JOIN
(SELECT id
FROM tbl FULL OUTER JOIN conditions c
WHERE c.isUseMe = 1 AND c.SEQ = 2 AND idTest=c.idTestVal AND result=c.resultVal) cond2 ON
cond1.id = cond2.id
if the 4 values are passed in as parameters, you'd need something like:
SELECT
id
FROM
(SELECT id
FROM tbl
WHERE idTest=#idTestVal1 AND result=#resultVal1) cond1 INNER JOIN
(SELECT id
FROM tbl
WHERE idTest=#idTestVal2 AND result=#resultVal2) cond2 ON
cond1.id = cond2.id