How to write a query to get only first matching row while joining two tables? - sql

Consider I have following tables:
Table 1:
AId
AMoniker
Table2:
BId
BMoniker
Table1->Table2 is one to many relationship
I want a temp table out of these two tables where if a particular Amoniker has multiple BMonikers then only first one should go in the table.
For example, if tables have following data:
Table1:
1 ABCD
2 DEFG
3 QWER
Table 2:
1 QZ
1 XC
1 CV
2 DE
2 OP
3 QW
the query should return the following:
ABCD QZ
DEFG DE
QWER QW
My query to get all the rows is:
select b.BMoniker, a.AMoniker
into #moniker_map
from Table1 a inner join Table2 b
on a.Aid=b.Bid
How can i modify this to get only 1st row from Table2 for each Id.
I tried following query:
select b.BMoniker, a.AMoniker
from Table1 a inner join Table2 b
on a.Aid=b.Bid
and b.BMoniker in
(
select top 1 BMoniker
from Table2
where Bid=cb.Bid
ORDER BY BMoniker
)
But i get following error:
Incorrect syntax near keyword 'top'
Sybase error code = 156, SQLState="ZZZZZ"

Selects row with minimum value from table2 (PostgreSQL syntax):
SELECT a.AMoniker, MIN(b.BMoniker) FROM Table1 a, Table2 b
WHERE a.Aid = b.Bid GROUP BY 1;

Maybe it is a typo but it looks like your subquery is referencing an table alias cb which is not defined. Can you try this:
select b.BMoniker, a.AMoniker
from Table1 a inner join Table2 b
on a.Aid=b.Bid
and b.BMoniker in
(
select top 1 BMoniker
from Table2 c
where c.Bid=a.Bid
ORDER BY BMoniker
)

Related

Delete a record from a table referring to 2 or more columns from another table

Consider having 2 tables as follows.
Table 1:
Unit
SKU number
Active
A
1
Y
B
2
Y
c
3
Y
Table 2:
Unit
SKU number
description
X
4
Apple
B
2
Mango
Y
5
Grapes
z
6
Banana
I wanted to delete record B,2,Y from table 1 by referring to table 2 where values in columns Unit and SKU number match.
I tried using the following query but it didn't seem to work
DELETE FROM table1
WHERE (Unit, SKU_Number) IN (SELECT Unit, SKU_Number FROM table2);
The error was
An expression of non-boolean type specified in a context where a condition is expected, near ','
Can someone please help me understand what I am doing wrong here or help me rewrite the SQL query to achieve the required objective?
You could use similar logic with exists:
DELETE
FROM table1 t1
WHERE EXISTS (SELECT 1 FROM table2 t2
WHERE t2.Unit = t1.Unit AND t2.SKU_Number = t1.SKU_Number);
You can try using this query, assuming Unit of Table 1 is unique:
DELETE FROM table1
WHERE table1.Unit IN (
SELECT table1.Unit
FROM table1
LEFT JOIN table2 ON table1.Unit = table2.Unit
AND table1.SKU_Number = table2.SKU_Number
)
If unit is not an unique field, simply replace it with whichever field is unique, or with primary key of Table 1.
You can use inner join for delete:
DELETE t1
FROM table1 t1
INNER JOIN table2 t2
ON t1.unit=t2.unit and t1.SKU_Number = t2.SKU.Number

merging two tables but removing duplicates in in a certain column

so I am trying to merge two tables for example
table 1:
name
col1
col2
David
W
C
BOB
v
w
table 2:
name
col1
col2
David
o
n
Kevin
l
x
Im trying to merge them such as if I have a duplicate name in table 1 and table 2, ill keep only the one in table 1
so table 3 would be like this
table 3:
left
center
right
David
W
C
Bob
v
w
Kevin
l
x
if I use union or union all, it creates 2 rows of David but I need only one of them
I think you want a full join:
select coalesce(t1.name, t2.name), t1.center, t2.right
from table_1 t1 full join
table_2 t2
on t1.name = t2.name;
I'm not clear what your goal is, if a match is found in col1/col2 in both tables. but try this:
SELECT
table1.name
,table1.col1
,table1.col2
,table2.col1
,table2.col2
FROM table_1 AS table1
FULL JOIN table_2 AS table2
ON table1.name = table2.name
This will join table_1 and table_2 on the name column
It will return null values in table1.col1/col2 and table2.col1/col2 if a match is not found

Count when value is in a column in another table

I have two tables
id
val
1
a
1
b
1
c
2
d
2
e
3
f
and
id
1
2
What I want is a count of the number of times an ID appears from the first table ONLY IF if it exists in the second table. How can I do this?
Example output:
id
count
1
3
2
2
3
0
Would you like to show ids that do not exist in the first table?
I made it show according to the ids that exist in the first table, if you want it to show up please comment below
select tb7.id, COUNT(tb6.id) as count
from Table_6 tb6 inner join Table_7 tb7 on tb6.id = tb7.id
group by tb7.id
You can use left outer join and count as follows:
Select t1.id, count(t2.id) as cnt
From table1 t1 left join
table2 t2
on t1.id = t2.id
Group by t1.id;

order by in UNION clauses existing a view in left join

I need to order the results by one attribute: Series (for each table). There is also a view in the queries...
The original query is:
select zz.Id
,t1.Series
,t1.SeriesType
from table 1 t1
inner join another_table (...)
left join view (...)
UNION
select zz.Id
,t2.Series
,t2.SeriesType
from table 2 t2
inner join another_table (...)
left join view (...)
UNION
select zz.Id
,t3.Series
,t3.SeriesType
from table 3 t3
inner join another_table (...)
left join view (...)
order zz.Id
this works, but only gives the order for zz.Id. How to achieve order for the Series column for each table?
I have tried with:
select *
from
(
SELECT TOP 100 PERCENT zz.Id
,t1.Series
,t1.SeriesType
from table 1 t1
inner join another_table (...)
left join view (...)
order by t1.Series) as table1
UNION
select *
from
(
SELECT TOP 100 PERCENT zz.Id
,t2.Series
,t2.SeriesType
from table 2 t2
inner join another_table (...)
left join view (...)
order by t2.Series) as table2
UNION
select *
from
(
SELECT TOP 100 PERCENT zz.Id
,t3.Series
,t3.SeriesType
from table 3 t3
inner join another_table (...)
left join view (...)
order by t3.Series) as table3
.
all tables are connected by one single table and this zz.id is unique for table1, table2, table3. (I see it is not possible to sort out at same time Id and series. so I will only sort out the series by each type of series). Thanks.
for example table 1 is:
zz.Id t1.series SERIES_Type
---------------------------------
1 4545 1
2 5655 1
3 2344 1
table 2
zz.Id t2.series SERIES_Type
---------------------------------
4 4546 2
table 3
zz.Id t3.series SERIES_Type
--------------------------------
5 545 3
6 343 3
7 2344 3
final result should be:
zz.Id series SERIES_Type
--------------------------------
3 2344 1
1 4545 1
2 5655 1
4 4546 2
6 343 3
5 545 3
7 2344 3
Have you tried two keys in the order by?
order Id, SeriestType
Based on your "expected result" all you need is:
order by SeriesType, Series
Am I correct or misunderstood...
Whenever it occurs to you to use "top 100 percent" - stop coding. This does nothing useful EVER. A resultset (which is the only way to look at rows) has no reliable or defined order unless the query that generated it included an order by clause. If you want to order rows according to each query within the union, then you need to add a column to each query that you can include in the final sort by clause.
As an example, this adds a column named srt (because "sort" is a reserved word - pick a name meaningful to you). Each participating query in the union is assigned a value that can be used to identify the "group". Again - make it meaningful to you. That column is included in the final sort by clause as the first column and will "group" rows.
use tempdb;
go
declare #tbl table (id int not null, series varchar(10) not null, seriestype varchar(10) not null);
insert #tbl(id, series, seriestype) values (1, '4521', 1), (1, '3011', 1), (2, '9999', 2), (3, '0000', 1), (3, '1111', 1);
select id, series, seriestype, 1 as srt from #tbl where id = 1
union all
select id, series, seriestype, 2 as srt from #tbl where id = 2
union all
select id, series, seriestype, 3 as srt from #tbl where id = 3
order by srt, id, series;
Now that you have updated your post, it seems you might be able to sort by seriestype. But that might be accidental due to your query logic and the data that exists in your tables. Only you can know if that is correct. TBH, I find the use of a union (vis-a-vis your sample output) suspicious.
And one final note. If you do not want to see the srt column in the final resultset, that can be arranged.

SQL Subquery Join and Sum

I have Table 1 & 2 with common Column name ID in both.
Table 1 has duplicate entries of rows which I was able to trim using:
SELECT DISTINCT
Table 2 has duplicate numeric entries(dollarspent) for ID's which I needed and was able to sum up:
Table 1 Table 2
------------ ------------------
ID spec ID Dol1 Dol2
54 A 54 1 0
54 A 54 2 1
55 B 55 0 2
56 C 55 3 0
-I need to join these two queries into one so I get a resultant JOIN of Table 1 & Table 2 ON column ID, (a) without duplicates in Table 1 & (b) Summed $ values from Table 2
For eg:
NewTable
----------------------------------------
ID Spec Dol1 Dol2
54 A 3 1
55 B 3 2
Notes : No. of rows in Table 1 and 2 are not the same.
Thanks
Use a derived table to get the distinct values from table1 and simply join to table 2 and use aggregation.
The issue you have is you have a M:M relationship between table1 and table2. You need it to be a 1:M for the summations to be accurate. Thus we derive t1 from table1 by using a select distinct to give us the unique records in the 1:M relationship (assuming specs are same for each ID)
SELECT T1.ID, T1.Spec, Sum(T2.Dol1) as Dol1, sum(T2.Dol2) as Dol2
FROM (SELECT distinct ID, spec
FROM table1) T1
INNER JOIN table2 T2
on t2.ID = T1.ID
GROUP BY T1.ID, T1.Spec
This does assume you only want records that exist in both. Otherwise we may need to use an (LEFT, RIGHT, or FULL) outer join; depending on desired results.
I can't really see your data, but you might want to try:
SELECT DISTINCT ID
FROM TblOne
UNION ALL
SELECT DISTINCT ID, SUM(Dol)
FROM TblTwo
GROUP BY ID
Pre-aggregate table 2 and then join:
select t1.id, t1.spec, t2.dol1, t2.dol2
from (select t2.id, sum(dol1) as dol1, sum(dol2) as dol2
from table2 t2
group by t2.id
) t2 join
(select distinct t1.id, t1.spec
from table1 t1
) t1
on t1.id = t2.id;
For your data examples, you don't need to pre-aggregate table 2. This gives the correct sums -- albeit in multiple rows -- if table1 has multiple specs for a given id.