I need to create a new table from data I extract from the following two tables:
First table:
Var cur_number
-------------------
A 10
B 8
Second table:
Var new_number
-------------------
A 2
A 11
B 4
B 6
The new table should contain a 'Var' column and a 'Number' column, where for each variable there will be one line with its cur_number, and the rest of the lines will contain the numbers from second table's new_number columns, where the new_number < cur_number.
For example, in the example shown above, for A there will be one line with 10 (its cur_number) and one line with '2' (since 2<10, however 11>10).
in my example the new table will be:
Var Number
A 10
A 2
B 8
B 4
B 6
The database is very large, and the running time is crucial so I cannot use UNION on the two tables...
This script assumes there is only one record per "Var" value in table1.
--insert all from table1
insert into newtable (var,number)
select var,cur_number from table1 t1
--insert from table2 where new_number < cur_number
insert into newtable (var,number)
select t2.var, t2.new_number
from table2 t2
inner join table1 t1 on t1.var = t2.var and t2.new_number < t1.cur_number
Try this:
SELECT var, cur_number
FROM FirstTable
UNION
SELECT t2.var, t2.new_number
FROM Firsttable t1
INNER JOIN SecondTable t2 ON t2.new_number < t1.cur_number;
Update: If you are using SQL Server 2008 or above, you can use MERGE to merge the two tables into one like so:
MERGE INTO FirstTable AS TGT
USING SecondTable AS SRC
ON SRC.new_number >= TGT.cur_number
WHEN NOT MATCHED THEN
INSERT (var, cur_number)
VALUES (SRC.var, SRC.new_number);
SQL Fiddle Demo
This will merge the two tables values into the first table. The first table will contains:
VAR CUR_NUMBER
A 10
B 8
A 2
B 4
B 6
Note that: When using MERGE:
You have to terminate the MERGE statement with a semicolon, It is mandatory.
You can't INSERT inside WHEN MATCHED thats why I used the reverse condition >= in the WHEN NOT MATCHED.
If you know for a fact that you do not have duplicate values in those 2 tables, then you can use UNION ALL instead of UNION
select * from table1 t1
UNION ALL
select* from table2 t2
where t2.new_number < t1.cur_number
By duplicate values, I mean something like this:
table1:
var cur_number
A 8
table2:
var new_number
A 8
The difference is that UNION ALL is faster than UNION, due to the fact that UNION eliminates duplicates from the resultset by using SELECT DISTINCT. In the case you have duplicates, UNION is the best in my experience.
Why not use Union? * SQLFIDDLE
select * from first
union
select s.var,s.new_number from second s
join first f
on s.var = f.var
join (
select f.var, max(f.cur_number) maxn
from first f
group by f.var) as t
on t.var = s.var
where s.new_number < t.maxn
order by var asc
;
results
VAR CUR_NUMBER
A 10
B 8
A 2
B 4
B 6
Related
I'm trying to match 2 tables using a SQL statement where attributes form one column are combined and the other values (delta) will be shown in the same row. For example the following 2 tables are given (which already result from some filtered and counted SQL querys):
Table 1:
Name
Count
First
4
Second
7
Third
2
Fourth
12
Fith
5
Table 2:
Name
Count
First
13
Second
6
Third
2
Fourth
12
Sixth
3
Expected result:
Name
Count table 1
Count table 2
First
4
13
Second
7
6
Third
2
2
Fourth
12
12
Fith
5
0
Sixth
0
3
Tried to use UNION and googled but don't get the needed result.
Should just be a simple join:
select table1.Name, table1.Count, table2.Count
from table1
join table2 on table1.Name = table2.Name
You need to use an inner join statement.
"SELECT [Table 1].Name, [Table 1].Count, [Table 2].count FROM [Table 1] INNER JOIN [Table 2] ON [Tabel 1].Name = [Table 2].Name"
You just try this one.
Create TABLE #A
(
name_a varchar(50),
column_a int
)
Create TABLE #B
(
name_b varchar(50),
column_b int
)
Insert INTO #A(name_a,column_a) values('First',4)
Insert INTO #A(name_a,column_a) values('Second',7)
Insert INTO #A(name_a,column_a) values('Third',2)
Insert INTO #A(name_a,column_a) values('Fourth',12)
Insert INTO #A(name_a,column_a) values('Fith',5)
Insert INTO #B(name_b,column_b) values('First',13)
Insert INTO #B(name_b,column_b) values('Second',6)
Insert INTO #B(name_b,column_b) values('Third',2)
Insert INTO #B(name_b,column_b) values('Fourth',12)
Insert INTO #B(name_b,column_b) values('Sixth',3)
select isnull(#A.name_a,#B.name_b) as Name, isnull(#A.column_a,0) as 'Count table 1', isnull(#B.column_b,0) as 'Count table 2'
from #A
full outer join #B on #A.name_a = #B.name_b
drop table #A
drop table #B
If you want to combine rows so as to get a result row consisting of the two original rows, then you join. In your case one data set may contain a name the other doesn't, so in your case a FULL OUTER JOIN may be appropriate. If it is guaranteed to find each name in both sets or you want to restrict the result to those names occurring in both sets, then INNER JOIN instead.
You say that the tables you are showing are query results. This is no problem, as you can join query results just as you join persisted database tables, because, well, a query result is a table, too.
select
name,
coalesce(q1.cnt, 0) as t1_count,
coalesce(q2.cnt, 0) as t2_count
from (select name, count(*) as cnt from t1 group by name) q1
full outer join (select name, count(*) as cnt from t2 group by name) q2 using (name)
order by name;
Based on your question, because one table can have name values that the other table does not, you could use FULL OUTER JOIN. You could try something like this:
SELECT
COALESCE(table1.Name, table2.Name) AS Name,
COALESCE(table1.Count,0) as "Count table 1",
COALESCE(table2.Count,0) as "Count table 2"
FROM
table1
FULL OUTER JOIN table2 ON table1.Name = table2.Name
;
I have two tables:
acc_num
ser_code
1
A
1
B
1
C
2
C
2
D
and the second one is:
ser_code
value
A
5
B
8
C
10
D
15
I want to exclude all the accounts with the service codes that they have value of 10 or 15.
Because my data set is huge, I want to use NOT EXIST but it just excludes combination of acc_num and ser_code.
I want to exclude the acc_num with all of it's ser_code, because on of it's ser_code meats my criteria.
I used:
select acc_num, ser_code
from table 1
where NOT EXIST (select 1
FROM table 2 where acc_num = acc_num and value in (10, 15)
out put with above code is:
acc_num
ser_code
1
A
1
B
Desire out put would be empty.
here you are
select t1.acc_num,t1.ser_code from table1 t1, table2 t2
where (t1.ser_code=t2.ser_code and t2.value not in (10,15))
and t1.acc_num not in
(
select t3.acc_num from table1 t3,table2 t4
where t1.acc_num=t3.acc_num and t3.ser_code=t4.ser_code
and t4.value in (10,15)
) ;
This could be achieved in many ways. However using NOT EXISTS is the best option. The problem with your query is for acc_num 1, there are ser_code that does not have value as 10, 15. So you will get A and B in result.
To overcome that you must pull acc_num inside the sub-query
Query 1 (using NOT EXISTS):
As you can see in the below query, I have included acc_num inside sub-query, so that the filter works properly,
SELECT DISTINCT a.acc_num, a.ser_code
FROM one as a
WHERE NOT EXISTS
(
SELECT DISTINCT one.acc_num
FROM two
INNER JOIN one
ON one.ser_code=two.ser_code
WHERE value IN (10,15) AND a.acc_num=one.acc_num
)
Query 2 (using LEFT JOIN):
NOT EXISTS often confusing due to it's nature (super fast though). Hence LEFT JOIN could also be used (expensive than NOT EXISTS),
SELECT DISTINCT a.acc_num, a.ser_code
FROM one as a
LEFT JOIN
(
SELECT DISTINCT one.acc_num
FROM two
INNER JOIN one
ON one.ser_code=two.ser_code
WHERE value IN (10,15)
) b
ON a.acc_num=b.acc_num
WHERE b.acc_num IS NULL
Query 3 (using NOT IN):
NOT IN would also achieve this with comprehensive query but expensive than both of the above methods,
SELECT DISTINCT a.acc_num, a.ser_code
FROM one as a
WHERE a.acc_num NOT IN
(
SELECT DISTINCT one.acc_num
FROM two
INNER JOIN one
ON one.ser_code=two.ser_code
WHERE value IN (10,15)
)
All 3 would yield same result. I would prefer to go with NOT EXISTS
See demo with time consumption in db<>fiddle
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.
I have two tables t1 and t2
table t1 as follows:
id name
1 x
2 y
3 z
table t2 as follows:
id name
1 a
121 b
131 c
Here I am selecting rows that are common in both the tables i.e.,
SELECT *
from t1,t2
where t1.id=t2.id;
Now I want to delete the rows when id=1 in both the tables at once. I have tried to delete the rows but I am able to delete only in one table but not both. Can anyone help me out in solving this.
You can do that with a data modifying common table expression
with common_ids as (
select id
from t1
intersect
select id
from t2
), t1_delete as (
delete from t1
where id in (select id from common_ids)
)
delete from t2
where id in (select id from common_ids);
Online example: http://rextester.com/NAQ26877
I have a task. For Instance, I have 2 tables.
Table 1 columns ID, Name
Table 2 columns ID, Name
Data is like in Table 1:
ID Name
1 A
2 B
3 C
Data is like in Table 2:
ID Name
1 D
2 B
3 E
I want to write a SQL query which lookup two tables in both columns. I want to have the count, which records not matching (both columns) with table 2.
Here only one record was matched (2 B). So, I should get the count 2.
Thanks.
Use not exists to count the # of rows in table1 that are not in table2
select count(*) from mytable t1
where not exists (
select 1 from mytable t2
where t2.id = t1.id
and t2.name = t1.name
)