SQL Inner join and Not in - sql

I am trying to run a query and not sure why the returned record set is off by 60 rows.
Select t1.* into #temp1
from NameExt as t1
join #temp1 as t2
on t1.AN = t2.AN --164172
Select t1.* into #temp3
from NameExt as t1
where AN in (Select AN from #temp1) --164112
When I do an intersect or except on #temp1 and #temp2, I dont get any rows back.
Really need to understand why the two queries are returning not a similar record set.
Even this returns the same number of rows as the 2nd query
Select * into #temp3 from NameExt as t1 where exists
( Select 1 from #temp1 as t2 where t1.AN = t2.AN) --164112
Thanks much

You can easily see what values are causing problems by doing:
select t2.AN
from #temp1 t2
group by t2.AN
having count(*) > 1;
Duplicates in the second table are causing the problem. You know how to fix it . . . using in or exists.

Your query is incorrect. You cannot select from and create a temp table at the same time..
Select t1.* into #temp1
from NameExt as t1
join #temp1 as t2
on t1.AN = t2.AN --164172

As per a comment, you likely have multiple rows in #temp1 with the same value in AN...
CREATE TABLE x (
id INT
)
CREATE TABLE y (
id INT,
x_id INT
)
INSERT INTO x VALUES (1), (2), (3)
INSERT INTO y VALUES (1, 2), (2, 2), (3, 3)
SELECT *
FROM x INNER JOIN y ON x.id = y.x_id
-- a total of three rows
-- x.id | y.id | y.x_id
------------------------
-- 2 | 1 | 2
-- 2 | 2 | 2
-- 3 | 3 | 3
SELECT *
FROM x
WHERE x.id IN (SELECT y.x_id FROM y)
-- a total of two rows
-- x.id
--------
-- 2
-- 3
http://sqlfiddle.com/#!18/7e1d1/2

Related

SQL - How to get duplicate records from one table with join on another table

I want to get records from Table1 where it has more than one record for same Access Number, but at the same time this Access Number should also be present in Table2.
Example
Table1
Access Number
- 1000
- 1000
- 1000
- 2000
- 3000
- 4000
- 5000
- 5000
Table2
AccessNumber Value
- 1000 -Value1000
- 1000 -Value9999
- 2000 -Value2000
- 3000 -Value3000
The result of the query should be 1000 - Value1000
This is what I've got so far, please suggest
SELECT a.AccessNumber, b.Valuefrom Table1 a
JOIN Table2 b on b.AccessNumber = a.AccessNumber
Group by a.AccessNumber, b.VAlue
HAVING COUNT(1) > 1;
The problem i am facing is the query returns duplicates from Table2.
1000 - Value1000
1000 - Value9999
Without much information as to why 1000 - Value1000 should be the result instead of 1000 - Value9999, we can just get the first record from the top:
select top 1 * from (
-- your original query
SELECT a.AccessNumber, b.Value from Table1 a
JOIN Table2 b on b.AccessNumber = a.AccessNumber
Group by a.AccessNumber, b.Value
HAVING COUNT(1) > 1
-- your original query
) as x;
If we are just looking for the AccessNumber that has duplicate records, you can remove the b.Value from the selected columns and remove that as well in the Group By clause.
SELECT a.AccessNumber from Table1 a
JOIN Table2 b on b.AccessNumber = a.AccessNumber
Group by a.AccessNumber
HAVING COUNT(1) > 1;
http://www.sqlfiddle.com/#!18/3f114/3
We might be able to get this working using SQL Server's EXCEPT operator. But one sensible way to go here would be to just aggregate both tables by access number, and then left join the first to the second, retaining only access numbers which appear in both tables and which appear in greater quantity in the first than the second.
SELECT t1.AccessNumber
FROM
(
SELECT AccessNumber, COUNT(*) AS cnt_1
FROM Table1
GROUP BY AccessNumber
) t1
LEFT JOIN
(
SELECT AccessNumber, COUNT(*) AS cnt_2
FROM Table2
GROUP BY AccessNumber
) t2
ON t1.AccessNumber = t2.AccessNumber
WHERE
t1.cnt_1 - COALESCE(t2.cnt_2, 0) > 0 AND t2.cnt_2 IS NOT NULL;
Demo
--Hope this query will help you
; with cte_accessnumber(Accessnumber, [value])
as
(
select
t1.Accessnumber, count(*)NoOfRecords
from table1 t1
where exists (
select top 1 1 from table2 t2 where t2.Accessnumber = t1.Accessnumber)
group by t1.Accessnumber
having count(*)>1
)
select t1.Accessnumber, t2.[value]
from cte_accessnumber t1
inner join table2 t2 on t2.Accessnumber = t1.Accessnumber and t2.[value] like '%' + convert(varchar(20),t1.Accessnumber) +'%'
you may try using nested for the criteria that AccessNumber rows > 1 and cross apply for criteria which only display 1 record
DECLARE #tblA AS TABLE
(
AccessNumber INT
)
DECLARE #tblB AS TABLE
(
AccessNumber INT,
colB NVARCHAR(50)
)
INSERT INTO #tblA SELECT 1000
INSERT INTO #tblA SELECT 1000
INSERT INTO #tblA SELECT 1000
INSERT INTO #tblA SELECT 1000
INSERT INTO #tblA SELECT 2000
INSERT INTO #tblA SELECT 3000
INSERT INTO #tblA SELECT 4000
INSERT INTO #tblB SELECT 1000,'hello'
INSERT INTO #tblB SELECT 1000,'hello2'
INSERT INTO #tblB SELECT 2000,'world'
-- Query --
SELECT tblB.* FROM (
SELECT AccessNumber,COUNT(1) AS cnt FROM #tblA GROUP BY AccessNumber ) ftblA
CROSS APPLY (SELECT TOP(1) * FROM #tblB itblB WHERE ftblA.AccessNumber = itblB.AccessNumber) tblB
WHERE ftblA.cnt >1
-- Only 1000 should be displayed only --
Use subquery with correlation approach
select access_no,
(select top 1 Value from table2 where access_no = t.access_no) as value
from Table1 t
where exists (
select 1 from table2 where access_no = t.access_no)
group by access_no
having count(*) > 1
However, you would need to specify order by clause in subquery in order to fetch the value from table2

Update table value by adding from other table

Can you please help me out with the below issue?
I have a table like below.
Table-1
Sales_RepID-- Name-- Products_Count
1-- ABC-- 2
2-- XYZ-- 4
3-- XXX-- 3
Table-2
Order_ID-- Sales_RepID-- Products_Count
1001-- 2 -- 2
1002-- 1 -- 1
1003-- 2 -- 1
1004-- 3 -- 3
1005-- 2 -- 2
Table - 1 Result
Sales_RepID, --Name, --Products_Count
1-- ABC --3
2-- XYZ --9
3-- XXX --6
I want to add table-2 Products_Count to Table-1 Products_Count for each Sale_RepID in the table-1
Can you please help with SQL Query?
My database is MS SQL SERVER
For MS SQL Server, please try:
UPDATE T
SET T.Products_Count=T.Products_Count+x.VSum
FROM Table1 T JOIN
(
SELECT DISTINCT
Sales_RepID,
SUM(Products_Count) OVER (PARTITION BY Sales_RepID) VSum
FROM
Table2
)x ON T.Sales_RepID=x.Sales_RepID
create table table1(sales_repId int,name varchar(10),product_count int);
create table table2(order_id int,sales_repId int,product_count int);
insert into table1 values(1,'ABC',2);
insert into table1 values(2,'XYZ',4);
insert into table1 values(3,'XXX',3);
insert into table2 values(1001,2,2);
insert into table2 values(1002,1,1);
insert into table2 values(1003,2,1);
insert into table2 values(1004,3,3);
insert into table2 values(1005,2,2);
select a.sales_repid,name,a.product_count+sum(b.product_count)
from table1 a
inner join table2 b
on a.sales_repid=b.sales_repid
group by a.sales_repid,name,a.product_count
order by a.sales_repid
UPDATE
update table1
set product_count = netProduct
from (
select a.sales_repid,name,a.product_count+sum(b.product_count) as netProduct
from table1 a
inner join table2 b
on a.sales_repid=b.sales_repid
group by a.sales_repid,name,a.product_count
) z
inner join table1 x
on z.sales_repid=x.sales_repid
TRY THIS
DECLARE #TABLE1 AS TABLE( Sales_RepID INT,Name VARCHAR(100), Products_Count int)
DECLARE #TABLE2 AS TABLE( Order_ID INT,Sales_RepID INT, Products_Count int)
INSERT INTO #TABLE1
VALUES(1,'ABC',2),(2,'XYZ',4),(3,'XXX',3)
INSERT INTO #TABLE2
VALUES(1001,2,2),(1002,1,1),(1003,2,1),(1004,3,3),(1005,2,2)
SELECT * FROM #TABLE1
SELECT * FROM #TABLE2
UPDATE T1
SET T1.Products_Count = T1.Products_count + total
FROM #TABLE1 T1
CROSS APPLY (
SELECT total= sum(Products_count)
FROM #Table2 T2
WHERE T1.Sales_RepID =t2.Sales_RepID ) Z
To output as a select:
select
t1.Sales_RepID,
t1.Name,
t1.Products_Count + sum(t2.Products_Count)
from table1 t1
left join table2 t2 on t2.Sales_RepID = t1.Sales_RepID
To update the total in table1, adding the total from table2:
update table1 set
Products_Count = Products_Count + (
select sum(Products_Count)
from table2
where Sales_RepID = table1.Sales_RepID)
These queries will work in all SQL dialects.
MS SQL Server has a special syntax for updating using a join, which will perform much better than the universal update syntax above:
update t1 set
t1.Products_Count = t1.Products_Count + t2.Products_Count
from table1 t1
join (select Sales_RepID, sum(Products_Count) Products_Count
from table2
group by Sales_RepID) t2
on t2.Sales_RepID = t1.Sales_RepID;
See a live demo of this update statement executing on SQLFiddle.
Note that this is an unusual query. Typically, such denormalized values are not cumulative: they are a determinable calculated value, which in this case wold be simply the sum, not the existing value plus the sum. Your design means that the query can only be executed once. After than you'll be repeatedly re-adding the total from table2.
Consider redesigning your tables to have the straight sum from table2 in table1, ie:
update t1 set
t1.Products_Count = t2.Products_Count
from table1 t1
join (select Sales_RepID, sum(Products_Count) Products_Count
from table2
group by Sales_RepID) t2
on t2.Sales_RepID = t1.Sales_RepID;

SQL joining on >=

I have a table like this in ORACLE
a b
-- --
1000 1
100 2
10 3
1 4
My other table has numbers like '67' or '112' in a column called numbers for example.
How can I join to this table using those values and get the correct result where >=1000 would be 1 and >= 100 would be 2 >=10 would be 3 etc.
I tried to do a
select g.b
from table o
join table2 g on o.column >= g.a
when I do this say 1002 was the value of g I would get the back these results.
1
2
3
4
when I just want 1
Easiest would be if your lookup table had ranges instead of just one number, such as row 1 = 1000,9999,1 and row 2 = 100,999,2 etc.
Then your join might be
SELECT OtherTable.n, lookup.b
from OtherTable
LEFT JOIN lookup on OtherTable.n between lookup.low and lookup.high
But, if you really want to use your original table, then on SQL Server, do this:
/*CREATE TABLE #A (a int,b int)
INSERT INTO #A VALUES (1000,1),(100,2),(10,3),(1,4)
CREATE TABLE #B (n INT)
INSERT INTO #B VALUES (67),(112),(4),(2001)
*/
SELECT B.n, A1.b
FROM #B B OUTER APPLY (SELECT TOP 1 a,b FROM #A A WHERE A.a<B.n ORDER BY A.a DESC) A1
Here's one way to do it using a subquery to get the MAX of column a, and then rejoining on the same table to get b:
select t.numericvalue, t2.b
from (
select t.numericvalue, max(t2.a) maxb
from table1 t
join table2 t2 on t.numericvalue >= t2.a
group by numericvalue
) t join table2 t2 on t.maxb = t2.a
SQL Fiddle Demo

SQLServer join two tables

I've gotta question for you, I'm getting hard times trying to combine two tables, I can't manage to find the correct query.
I have two tables:
T1: 1column, Has X records
T2: 1column, Has Y records
Note: Y could never be greater than X but it often lesser than this one
I want to join those tables in order to have a table with two columns
t3: ColumnFromT1, columnFromT2.
When Y is lesser than X, the T2 field values gets repeated and are spread over all my other values, but I want to get NULL when ALL the columns from T2 are used.
How could I achieve that?
Thanks
You could give each table a row number in a subquery. Then you can left join on that row number. To recycle rows from the second table, take the modulus % of the first table's row number.
Example:
select Sub1.col1
, Sub2.col1
from (
select row_number() over (order by col1) as rn
, *
from #T1
) Sub1
left join
(
select row_number() over (order by col1) as rn
, *
from #T2
) Sub2
on (Sub1.rn - 1) % (select count(*) from #T2) + 1 = Sub2.rn
Test data:
declare #t1 table (col1 int)
declare #t2 table (col1 datetime)
insert #t1 values (1), (2), (3), (4), (5)
insert #t2 values ('2010-01-01'), ('2012-02-02')
This prints:
1 2010-01-01
2 2012-02-02
3 2010-01-01
4 2012-02-02
5 2010-01-01
You are looking for a LEFT JOIN (http://www.w3schools.com/sql/sql_join_left.asp) eg . T1 LEFT JOIN T2
say they both have column CustomerID in common
SELECT *
FROM T1
LEFT JOIN
T2 on t1.CustomerId = T2.CustomerId
This will return all records in T1 and those that match in T2 with nulls for the T2 values where they do not match.
Make sure you are joining the tables on a common column (or common column set if more than one column are necessary to perform the join). If not, you are doing a cartesian join ( http://ezinearticles.com/?What-is-a-Cartesian-Join?&id=3560672 )

SQL: Select lowest value that doesn't already exist

In TableA I have an int column.
Is it possible using only a select statement to select the minimum value in the column that DOES NOT EXIST and is greater then 0?
For example, if the col has the values 1,2,9 the select statement will return 3.
If the col has 9,10,11 it will return 1.
I can achieve this using a temp table or using a loop, but I'm wondering if I can do it using just a select statement?
SELECT MIN(t1.ID+1) as 'MinID'
FROM table t1 LEFT JOIN table t2
On t1.ID+1=t2.ID
Where t2.OtherField IS NULL
select
min(nt.id)
from numbertable nt
left outer join originaldata od
on nt.id=od.id
where od.id is null
have a number table that goes from 1 to your max value (or higher)
SELECT DISTINCT x + 1 "val"
EXCEPT SELECT DISTINCT x "val"
ORDER BY "val" ASC
LIMIT 1
What about this?
SELECT Min(id)
FROM (SELECT 1 id
FROM tablea
WHERE 1 NOT IN (SELECT id
FROM tablea)
UNION
SELECT id + 1 id
FROM tablea
WHERE id + 1 NOT IN (SELECT id
FROM tablea)) AS min_ids;
try this:(Updated)
declare #dummy varchar(10) ;
set #dummy =(select top(1) id from dbo.b)
if( #dummy= '1')
begin
select top(1)l.id + 1 as start
from dbo.b as l
left outer join dbo.b as r on l.id + 1 = r.id
where r.id is null
end
else
begin
select '1'
end
Give this a try:
declare #TestTable table (
col int
)
/* Test Case 1: 1,2,9 */
insert into #TestTable
(col)
select 1 union all select 2 union all select 9
SELECT MinValue = (SELECT ISNULL(MAX(t2.col),0)+1
FROM #TestTable t2
WHERE t2.col < t1.col)
FROM #TestTable t1
WHERE t1.col - 1 NOT IN (SELECT col FROM #TestTable)
AND t1.col - 1 > 0
delete from #TestTable
/* Test Case 2: 9,10,11 */
insert into #TestTable
(col)
select 9 union all select 10 union all select 11
SELECT MinValue = (SELECT ISNULL(MAX(t2.col),0)+1
FROM #TestTable t2
WHERE t2.col < t1.col)
FROM #TestTable t1
WHERE t1.col - 1 NOT IN (SELECT col FROM #TestTable)
AND t1.col - 1 > 0
I duplicated my answer from here:
SELECT MIN(a.id) + 1 AS firstfree
FROM (SELECT id FROM table UNION SELECT 0) a
LEFT JOIN table b ON b.id = a.id + 1
WHERE b.id IS NULL
This handles all cases I can think of - including no existing records at all.
The only thing I don't like about this solution is that additional conditions have to be included twice, like that:
SELECT MIN(a.id) + 1 AS firstfree
FROM (SELECT id FROM table WHERE column = 4711 UNION SELECT 0) a
LEFT JOIN table b ON b.column = 4711 AND b.id = a.id + 1
WHERE b.id IS NULL
Please also notice the comments about locking and concurrency - the requirement to fill gaps is in most cases bad design and can cause problems. However, I had a good reason to do it: the IDs are to be printed and typed by humans and we don't want to have IDs with many digits after some time, while all the low ones are free...