CREATE TABLE dbo.Temp_Test
(Main_id int,
Unique_id char(1) )
insert into Temp_Test(Main_id,Unique_id)
values (1, 'a'),
(2, 'b'),
(3, 'c'),
(4, 'c')
SELECT r.Main_Id, r.Unique_ID, x.Main_Id, x.Unique_id
FROM dbo.Temp_Test r
LEFT JOIN dbo.Temp_Test x
ON r.Unique_ID = x.Unique_ID
AND x.Main_Id < r.Main_Id
WHERE x.Main_Id IS NULL
I'm trying to understand how this query works. When running it in steps, it just made me more confused. When it's ran just as
SELECT r.Main_Id, r.Unique_ID, x.Main_Id, x.Unique_id
FROM dbo.Temp_Test r
LEFT JOIN dbo.Temp_Test x
ON r.Unique_ID = x.Unique_ID
the results turn into
Main_ID Unique_ID Main_id Unique_id
1 a 1 a
2 b 2 b
3 c 3 c
3 c 4 c
4 c 3 c
4 c 4 c
But when ran with the x.main_id < r.main_id filter, we get
Main_ID Unique_ID Main_id Unique_id
1 a NULL NULL
2 b NULL NULL
3 c NULL NULL
4 c 3 c
What happened to the 4 C 4 C row?
When you do left join, all the records from the left table will be part of the result. If query finds match from second table, it will show them in result or else will simply print NULL.
In first query, it did find an match with Unique_id's so it gave you results with all possible pairs.
In second query, since there were no records where Main_id was greater in first table (for 1,2,3) it returned NULL for second table.
Whereas, it found Main Id 4 from table at the left to be greater than 3 from table at the right so it displayed the result.
Since Main_id 4 from left table is not greater than the Main_id 4 from the right table, that is not a part of the result.
Related
I need a recommendation.
I have two tables. Table 1 is the main table and table 2 is the table that I initially thought to join Table 1 through a left join, table 2 is much larger than table 1. What would be the best performing way to join Table 1 and Table 2 being the union condition that Column b is equal to column b or that column c is equal to column c and column d is equal to column d, that is, any of these conditions is met but no empty values are met. This without using OR in the left join due to the poor performance it would have and the execution time. I appreciate any help.
Note: table 1 and table 2 is the result of 40 lines query. Database do not support recursive query. The database is sap hana.
Table 1
ID
column b
column c
column d
1
d
g
j
2
e
h
k
3
f
i
Table 2
ID_2
column b
column c
column d
4
d
g
5
k
6
i
Desired Result
ID
column b
column c
column d
ID_2
1
d
g
J
4
2
e
h
k
5
3
f
i
6
Use two left joins:
select t1.*,
coalesce(t2_b.id_2, t2_c.id_2, t2_d.id_2) as id_2
from table1 t1 left join
table2 t2_b
on t1.b = t2_b.b left join
table2 t2_c
on t1.c = t2_d.c and t2_b.b is null
table2 t2_d
on t1.d = t2_d.d and t2_c.c is null;
Note that for optimal performance, you want three indexes:
table2(b, id_2)
table2(c, id_2)
table2(d, id_2)
I have these 3 tables
Table 1:
id_Table1 field_table1_1 field_table1_2
1 A B
2 C D
3 E F
Table 1:
id_Table2 field_table2_1 field_table2_2
4 G H
5 I J
List item
Table 3:
id_Table3 id_Table1 id_Table2
1 1 4
2 1 5
3 2 5
So table 3 holds the relation between table 1 and 2.
What I want to do, is with a query, get all the fields in the table 1, plus one extra field that contains all the ids of the table 2 separated by coma.
So the result should be something like this:
id_Table1 field_table1_1 field_table1_2 id_Table2
1 A B 4, 5
2 C D 5
3 E F
One option use a lateral join and string_agg():
select t1.*, x.*
from table1 t1
outer apply (
select string_agg(t3.id_table2) id_table2
from table3 t3
where t3.id_table1 = t1.id_table1
) x
There is no need to bring table2 to get the results you want.
I have bug in my query, but I have no idea what happen.
So there is 3 tables.
table 1
name grade min max
a
b
c
d
e
table 2
fullname name min max
a a123 1 10
bbbb b 2 20
c cccc 3 30
d dd 1 10
E Ed 2 20
table 3
value grade
25 A
15 B
5 C
my goal is using name, show the grade of the name( the max > value in table 3).
for example, c has 30 in max, it should have A grade, instead of B and C.
Also, the name usually is the fullname in table 2, but sometime it is name in the table2(like b)(here is one of bugs). That's how the table look like, I can't change it.
if I am not include the checking table 1.name = table 2.name . no bug at all, but cannot get grade for b
if i include the table 1.name = table 2.name.then, it has problem
for the query of matching the grade, it is like(assume get the min and max from table 2 before)
update table1
set table1.grade = table3.grade
from table1 inner join table3
on table1.max > table3.value
All the cases are include the checking table 1.name = table 2.name
case 1:
the grade will equal = C for all data if there is some data inlcude.
for example, in table1, if I am not include E, then everything is fine.
but if I include E, will get C grade for all records.
case 2:
if I run the query for all data at the same time, the result goes wrong.
it work fine if I update the record one by one.,
for example, i add one more condition in update query
update table1
set table1.grade = table3.grade
from table1 inner join table3
on table1.max > table3.value and fullname='c'
after getting wrong result, i add the condition and run it again,
then c will get grade 'A' instead of 'C'. but if I remove the condition and run the query again.
c will get grade 'C' again.
case 3:
there is no problem when I only run the set of data that will cause case 1 problem independently.
but if I put the data together, It cases problem.
That is all cases. I don't know what cause the problem. Please help
The result should be:
table 1
name grade min max
a C 1 10
b B 2 20
c A 3 30
d C 1 10
e B 2 20
If I remove table1.name = table2.name, result will be
table 1
name grade min max
a C 1 10
b null null null
c A 3 30
d C 1 10
e B 2 20
with table1.name = table2.name, result will be
table 1
name grade min max
a C 1 10
b C 2 20
c C 3 30
d C 1 10
e C 2 20
with table1.name = table2.name but remove e , result will be
table 1
name grade min max
a C 1 10
b B 2 20
c A 3 30
d C 1 10
with table1.name = table2.name but only for e,result will be
name grade min max
e B 2 20
those situation happen when I run the update query for whole table.
there is no problem with table1.name = table2.name if I update each row one by one.
At the very least, you should avoid the way you update the table. You should be carefull with joins on update. If you happen to have more than one value for the same row, the result is not deterministic. Better use this form:
update table1
set table1.grade = (SELECT TOP 1 table3.grade FROM table3
WHERE table3.value < table1.max
ORDER BY table3.value DESC)
I am not sure about the expected results but you may have traced the problem already: incorrect criteria.
Before doing an update, just try a select with the same criteria eg:
select *
from table1 inner join table3
on table1.max > table3.value
and see what you get.
I have 2 tables with the same structure.
FIELD 1 INT
FIELD 2 VARCHAR(32) -- is a MD5 Hash
The query has to get matching FIELD 1 pairs from for records that have the exact combination of values for FIELD 2 in both TABLE 1 and TABLE 2.
These tables are pretty large ( 1 million records between the two ) but are deduced down to an ID and a Hash.
Example data:
TABLE 1
1 A
1 B
2 A
2 D
2 E
3 G
3 H
4 E
4 D
4 C
5 E
5 D
TABLE 2
8 A
8 B
9 E
9 D
9 C
10 F
11 G
11 H
12 B
12 D
13 A
13 B
14 E
14 A
The results of the query should be
8 1
9 4
11 3
13 1
I have tried creating a concatenated string of FIELD 2 using a correlated sub-query and FOR XML PATH string trick I read on here but that is very slow.
You can try following query also -
SELECT t_2.Field_1, t_1.Field_1 --1
FROM table_1 t_1, table_2 t_2 --2
WHERE t_1.Field_2 = t_2.Field_2 --3
GROUP BY t_1.Field_1, t_2.Field_1 --4
HAVING COUNT(*) = (SELECT COUNT(*) --5
FROM Table_1 t_1_1 --6
WHERE t_1_1.Field_1 = t_1.Field_1) --7
AND COUNT(*) = (SELECT COUNT(*) --8
FROM Table_2 t_2_1 --9
WHERE t_2_1.Field_1 =t_2.Field_1) --10
Edit
First the requested set of result is the combination of Field1 from both the tables where respective Field2 is exactly same.
so for that you can use one method which I have posted above.
Here
query will take the data from both the table based on field2 values (from line 1 to line 3)
then it will group the data based on field1 from table1 and field1 from table2 (line 4)
till this step you will get the result having field1 from table1 and field2 from table2 where it exists (at least one) matching based on field2 from tables for respective field1 values.
after this you just need to filter the result for correct (exactly same values for field2 values for respective field1 column value). so that you can make condition on row count.
here my assumption is that you don't have multiple values for field1 and field2 combination in either tables
means following rows will not be present -
1 b
1 b
In any of the tables.
if so, the rows count got for table1 and table2 for same field2 values should be match with the rows present in table1 for field1 and same rows only should present in tables2 for field2 value.
for this condition query has condition on count(*) in having clause (from line 5 to line 10).
Let me try to explain this version of the query:
select t1.field1 as t1field1, t2.field1 as t2field1
from (select t1.*,
count(*) over (partition by field1) as NumField2
from table1 t1
) t1 full outer join
(select t2.*,
count(*) over (partition by field1) as NumField2
from table2 t2
) t2
on t1.field2 = t2.field2
where t1.NumField2 = t2.NumField2
group by t1.Field1, t2.Field1
having count(t1.field2) = max(t1.NumField2) and
count(t2.field2) = max(t2.NumField2)
(which is here at SQLFiddle).
The idea is to compare the following counts for each pair of field1 values.
The number of field2 values on each.
The number of field2 values that they share.
All of these have to be equal.
Each subquery counts the number of values of field2 on each field1 value. For the first rows of your data, this produces:
1 A 2
1 B 2
2 A 3
2 D 3
2 E 3
. . .
And for the second table
8 A 2
8 B 2
9 E 3
9 D 3
9 C 3
Next, the full outer join is applied, requiring a match on both the count and the field2 value. This multiplies the data, producing rows such as:
1 A 2 8 A 2
1 B 2 8 B 2
2 A 3 NULL NULL NULL
2 D 3 9 D 3
2 E 3 9 E 3
NULL NULL NULL 9 C 3
And so on for all the possible combinations. Note that the NULLs appear due to the full outer join.
Note that when you have a pair, such as 1 and 8 that match, there are no rows with NULL values. When you have a pair with the same counts but they don't match, then you have NULL values. When you have a pair with different counts, they are filtered out by the where clause.
The filtering aggregation step applies these rules to get pairs that meet the first condition but not the second.
The having essentially removes any pair that has NULL values. When you count() a column, NULL values are not included. In that case, the count() on the column is fewer than the number of values expected (NumField2).
I have two tables as given below
Table A Table B Table C
============= ============== =========
Id Name Id AId CId Id Name
1 A 1 1 1 1 x
2 B 2 1 1 2 y
3 C 3 2 1 3 z
4 D 4 2 3 4 w
5 E 5 3 2 5 v
Now I want all the records of Table A with matching Id column CId from Table B where CId = 1.
So the output should be like below :
Id Name CId
1 A 1
2 B 1
3 C 1
4 D Null
5 E Null
Can anyone help me please?
This does what you want:
SELECT
A.Id,
A.Name,
CASE B.CId WHEN 1 THEN 1 ELSE NULL END AS CId
FROM
A LEFT JOIN B ON A.Id = B.Id
This is not about LEFT JOINing. You could as well do it with an INNER JOIN. When you don't want the 3 and 2 of column CId to appear you would still have to filter with WHERE and therefore the rows with Id 4 and 5 would not appear, which is not what you want.
EDIT:
Given this test data:
create table A (Id int, Name varchar(5));
insert into A values
(1, 'A'),
(2, 'B'),
(3, 'C'),
(4, 'D'),
(5, 'E');
create table B (Id int, AId int, CId int);
insert into B values
(1,1,1),
(2,1,1),
(3,2,1),
(4,2,3),
(5,3,2);
my query does not give a cartesian product. Read and try before downvoting. Anyway, it was not clear to me what you want to achieve, now I've joined on AId column and with this query:
SELECT DISTINCT
A.Id,
A.Name
, CASE
WHEN B.CId > 1 THEN 1
WHEN B.CId = 1 THEN 1
ELSE NULL END AS CId
FROM
A LEFT JOIN B ON A.Id = B.AId
and it also gives the right output, like the first before. If this is still not what you want, your test data is wrong or I absolutely don't get it.
Try something like this:
SELECT TableA.Id, TableA.Name, TableB.CId
FROM TableA
LEFT OUTER JOIN TableB ON TableA.Id = TableB.CId
WHERE TableB.CId = 1
Hope this helps.
Edit:
The output you desired, can be achieved if you match TableA's ID column with TableB's ID column, NOT TableB's CId column. Try below which I tested in my pc and gives thee similar output you needed.
select TableA.Id, TableA.Name, TableB.CId
from TableA
left outer join TableB on TableA.Id = TableB.Id
and TableB.CId in
(
select TableB.CId
from TableB
left outer join TableC on TableB.CId = TableC.Id
WHERE TableB.CId = 1
)
group by TableA.Id, TableA.Name, TableB.CId
Please inform if I guess it right. Check the column names.