I have 2 tables T1 and T2.
T1:
ID | Name
----+-------
A | A1
A | C1
T2:
ID | Name
-----+------
A | A1
A | B1
I want to retrieve records that have same ID and Name with flag 1 and Same ID and Different Name with flag 0. However, while joining the table in SQL Server, I am getting the a cross join which is:
A | A1 | A1 | 1
A | A1 | B1 | 0
A | C1 | A1 | 0
A | C1 | B1 | 0
But I need the answer as:
A | A1 | A1 | 1
A | C1 | B1 | 0
The above result is giving me the same information about name mismatch but in limited no. of rows and no repetition.
Could somebody let me know how can do this in SQL Server?
Is this what you're after:
SELECT T1.ID, T1.Name Name1, T2.Name Name2, case T1.Name when T2.Name then 1 else 0 end Result
from T1
inner join T2 on T1.ID = T2.ID
where T1.Name = T2.Name
or (not exists (select 1 from T2 where T1.Name = Name and T1.ID = ID)
and not exists (select 1 from T1 where T2.Name = Name and T2.ID = ID))
Use a union to keep things simple:
select T1.ID, T1.Name Name1, T2.Name Name2, 1 flag
from T1
join T2 on T1.ID = T2.ID
and T1.Name = T2.Name
union all
select T1.ID, T1.Name, T2.Name, 0
from T1
join T2 on T1.ID = T2.ID
and T1.Name != T2.Name
Using a union is not the most efficient way, but it’s much easier to understand and unless you have millions of rows, it will still run very fast (and union all is quite a bit faster than union)
you can use ROW_NUMBER and FULL JOIN
DECLARE #T1 TABLE (ID VARCHAR(5), Name VARCHAR(5))
INSERT INTO #T1 VALUES ('A', 'A1')
INSERT INTO #T1 VALUES('A', 'C1')
DECLARE #T2 TABLE (ID VARCHAR(5), Name VARCHAR(5))
INSERT INTO #T2 VALUES ('A', 'A1')
INSERT INTO #T2 VALUES ('A', 'B1')
SELECT T1.ID, T1.Name, T2.Name, CASE WHEN T1.Name = T2.Name THEN 1 ELSE 0 END
FROM
( SELECT ROW_NUMBER()OVER(PARTITION BY ID ORDER BY Name) AS RN, * FROM #T1 ) T1
FULL JOIN
( SELECT ROW_NUMBER()OVER(PARTITION BY ID ORDER BY Name) AS RN, * FROM #T2 ) T2
ON T1.ID = T2.ID AND T1.RN = T2.RN
Result:
ID Name Name
----- ----- ----- -----------
A A1 A1 1
A C1 B1 0
Related
T1 is a table of company and their (multiple users), T2 is table of registered users. I counted, for each company in T1, how many of their users are in T2 but need c3 to appear in the result table with #regUser == 0:
T1:
company user
c1 u1
c1 u2
c2 u2
c2 u3
c3 u4
c3 u1
T2:
user
u2
u3
So the resultant table should look like:
company #regUser
c1 1
c2 2
c3 0
With the following code I'm only getting the results for non-null companies:
select t1s.company, count(1)
from (select * from t1) t1s
cross apply (select *
from t2 t2s
where t2s.reguser = t1s.[user]) t12s
group by t1s.company
Thanks
just use left join
select t1.company,count(t2.user)
from t1 left join t2 on t1.user=t2.user
group by t1.company
the subquery is not necessary according to your requirement
but if you want to use apply then you need like below query
select t1s.company, count(t12s.Users)
from (select * from t1) t1s
outer apply (select Users
from t2 t2s
where t2s.Users = t1s.[Users]) t12s
group by t1s.company
output
company #regUser
c1 1
c2 2
c3 0
demolink
You can use a LEFT JOIN to get all the information of the left table with matching information from right table. By using a GROUP BY you can group the rows by company and get the COUNT of registered users for each company:
SELECT t1.company, COUNT(t2.[user]) AS regUser
FROM t1 LEFT JOIN t2 ON t1.[user] = t2.[user]
GROUP BY t1.company
ORDER BY t1.company ASC
You can also use the CROSS APPLY to solve this:
SELECT t1.company, SUM(CASE WHEN t1.[user] = t2.[user] THEN 1 ELSE 0 END) AS regUser
FROM t1 CROSS APPLY t2
GROUP BY t1.company
ORDER BY t1.company ASC
demo on dbfiddle.uk
All you need is a left join :
select company,count(t2.[user])
from t1 left outer join t2 on t1.[user]=t2.[user]
group by company
The question's query is overcomplicated. For example, from (select * from t1) t1s is equivalent to from t1 as t1s.
Just a LEFT JOIN with SUM()
CREATE TABLE T1(
Company VARCHAR(20),
Users VARCHAR(20)
);
CREATE TABLE T2(
Users VARCHAR(20)
);
INSERT INTO T1 VALUES
('c1', 'u1'),
('c1', 'u2'),
('c2', 'u2'),
('c2', 'u3'),
('c3', 'u4'),
('c3', 'u1');
INSERT INTO T2 VALUES
('u2'),
('u3');
SELECT T1.Company,
SUM(CASE WHEN T2.Users IS NULL THEN 0 ELSE 1 END) Cnt
FROM T1 LEFT JOIN T2
ON T1.Users = T2.Users
GROUP BY T1.Company;
Returns:
+---------+-----+
| Company | Cnt |
+---------+-----+
| c1 | 1 |
| c2 | 2 |
| c3 | 0 |
+---------+-----+
Live Demo
I have 2 tables.
Tabel T1:
-----ID-----Name----
1 P1
2 P2
3 P3
Tabel T2:
-----ID-----PID----Type
1 1 T1
1 2 T2
1 3 T1
2 4 T3
2 5 T3
What I want:
----Name----Different_Types-----Type_Names
P1 2 T1,T2
What I have tried:
Select distinct T1.NAME,
count(distinct T2.Type) as Different_Types,
from T1
left join T2
on T2.ID = T1.ID
having count(distinct T2.PID) > 2
order by Different_Types desc
Whit this query I have the two first columns in my desired table, but having trouble adding the third....Any idea's ?
Think this should do what you are after
DECLARE #T1 TABLE
(
ID INT NOT NULL,
Name CHAR(2) NOT NULL
);
INSERT INTO #T1
VALUES (1,'P1'),(2,'P2'),(3,'P3');
DECLARE #T2 TABLE
(
ID INT NOT NULL,
PID INT NOT NULL,
TypeName CHAR(2) NOT NULL
);
INSERT INTO #T2
VALUES (1,1,'T1'),(1,2,'T2'),(1,3,'T1'),(2,4,'T3'),(2,5,'T3');
SELECT T1.Name,
COUNT(DISTINCT T2.TypeName) AS Different_Types,
STUFF((
SELECT ',' + T.TypeName
FROM #T2 AS T
WHERE T1.ID = T.ID
GROUP BY T.TypeName
FOR XML PATH(''), TYPE).value('.', 'varchar(max)')
,1,1,'')
FROM #T1 AS T1
INNER
JOIN #T2 AS T2
ON T1.ID = T2.ID
GROUP BY T1.ID, T1.Name
HAVING COUNT(DISTINCT T2.PID) > 2;
Edit:
Changed your LEFT to an INNER join as you are referencing the T2 table in the having clause anyway.
I feel like there should be an easy way to do this.
Given two tables (ID is primary key, no duplicates):
TblQtyNew TblQtyUsed
ID | QtyNew ID | QtyUsed
1 15 1 7
2 18 3 21
How can I obtain the following result?
ID | QtyNew | QtyUsed
1 15 7
2 18 NULL
3 NULL 21
The only solution I have come up with involves a UNION on the ID column then two left joins:
(SELECT ID FROM TblQtyNew) UNION (SELECT ID FROM TblQtyUsed) as IDs
LEFT JOIN
(SELECT QtyNew FROM TblQtyNew) ON TblQtyNew.ID = IDs.ID
LEFT JOIN
(SELECT QtyUsed FROM TblQtyUsed) ON TblQtyUsed.ID = IDs.ID
Is there a more simple way to do this?
You can use full join and coalesce in id as below:
select coalesce(t1.id,t2.id) as Id, Qtynew, QtYused
from #table1 t1 full join #table2 t2
on t1.id = t2.id
Output:
+----+--------+---------+
| Id | Qtynew | QtYused |
+----+--------+---------+
| 1 | 15 | 7 |
| 2 | 18 | NULL |
| 3 | NULL | 21 |
+----+--------+---------+
You want a FULL OUTER JOIN:
SELECT COALESCE(T1.ID,T2.ID) as ID, T1.QtyNew, T2.QtyUsed
FROM TblQtyNew T1
FULL OUTER JOIN TblQtyUsed T2 on T1.ID = T2.ID
1.
SELECT ID,SUM(ISNULL(QtyNew)) AS QtyNew,SUM(ISNULL(QtyUsed)) AS QtyUsed
FROM (
SELECT ID,QtyNew,NULL AS QtyUsed FROM TblQtyNew
UNION ALL
SELECT ID,NULL QtyNew, QtyUsed FROM TblQtyUsed
) AS t
GROUP BY ID
2.
SELECT COALESCE(n.ID,U.ID) AS ID,n.QtyNew,u.QtyUsed
FROM TblQtyNew AS n FULL OUTER JOIN TblQtyUsed AS u ON n.ID=u.ID
Use FULL JOIN and Case:
DECLARE #T1 TABLE (id int , QtyNew int);
DECLARE #T2 TABLE( id int , QtyUsed int);
insert into #T1 values (1,15),(2,18);
insert into #T2 values (1,7),(3,21);
SELECT ID = case when T1.ID IS not Null then T1.ID else T2.ID end, T1.QtyNew, T2.QtyUsed
FROM #T1 T1
full JOIN #T2 T2 on T1.ID = T2.ID
Order by ID;
Demo
I intentionally trying alternate method.
declare #TblQtyNew table (ID int,QtyNew int)
insert into #TblQtyNew VALUES
(1,15)
,(2,18)
declare #TblQtyUsed table ( ID int, QtyUsed int)
insert into #TblQtyUsed VALUES
(1 ,7 )
,(3 ,21)
;with CTE as
(
select a.id,QtyNew,b.QtyUsed from #TblQtyNew a
inner join #TblQtyUsed b on a.id=b.ID
)
select * from CTE
union all
select a.id,QtyNew,null
from #TblQtyNew a
where not exists(select id from cte c where c.id=a.id)
union all
select a.id,null,QtyUsed
from #TblQtyUsed a
where not exists(select id from cte c where c.id=a.id)
select Id, QtyNew, QtyUsed
from TblQtyNew Full outer join TblQtyUsed
on TblQtyNew.ID=TBLQtyUsed.ID
I have an issue regarding conditional inner join. Kindly have a look at the following sqlfiddle.
http://sqlfiddle.com/#!4/6dc88
Here i'm trying to get all the same name. but if in case the id is 1 then also get the same name and the name which has id of 0. Your help will be appriciated. thanks. here is the example
Table1
Id | Name
1 | A
2 | B
3 | C
Table2
Id | Name
1 | a
2 | b
3 | c
0 | d
Here is what i expect
A | a
B | b
C | c
A | d
Edit: Sorry i forget to mention my query, here is what i have tried so far..
select t1.name, t2.name from table1 t1
inner join table2 t2 on
CASE
WHEN t1.id = t2.id_copy and t1.id = 1 THEN
0
else
t1.id
END = t2.id_copy
Thanks in advance.
Assuming you mean that if table2.id is 0 then it should match with table1.id = 1, then this should do the trick:
with table1 as (select 1 id, 'A' name from dual union all
select 2 id, 'B' name from dual union all
select 3 id, 'C' name from dual),
table2 as (select 1 id, 'a' name from dual union all
select 2 id, 'b' name from dual union all
select 3 id, 'c' name from dual union all
select 0 id, 'd' name from dual)
select t1.name, t2.name
from table1 t1
inner join table2 t2 on (t1.id = case when t2.id = 0 then 1 else t2.id end);
NAME NAME_1
---- ------
A a
B b
C c
A d
If there's more complicated logic around what decides how non-matching (t1.id = t2.id) rows in table2 match with table1, then you'll have to explain the logic.
Personally I would prefer to use something simpler, like:
select t1.name, t2.name from table1 t1
inner join table2 t2
on t1.id = t2.id_copy or (t1.id = 1 and t2.id_copy = 0)
I am using SQL Server 2008. I have two tables, Table1 and Table2 as below.
Table1
ID Col1 Col2 Col3
-- ---- ---- ----
1 X Y Z
Table2
ID Col1 Col2 Col3
-- ---- ---- ----
1 1 2 3
I want to write a stored procedure, to return result something like below. And have to achieve this result without using cursor.
Result
Key Value
--- -----
X 1
Y 2
Z 3
Edited:
I required one result set.
Both IDs are parameter of my Store Procedure.
Since you are using SQL Server 2008, you can use CROSS APPLY with VALUES to unpivot data. You can first JOIN the two table on the id column and then unpivot it into the key/value columns:
select [key], value
from
(
select t1.col1, t2.col1 t2_col1,
t1.col2, t2.col2 t2_col2,
t1.col3, t2.col3 t2_col3
from table1 t1
inner join table2 t2
on t1.id = t2.id
) src
cross apply
(
values
(col1, t2_col1),
(col2, t2_col2),
(col3, t2_col3)
) c ([key], value);
See SQL Fiddle with Demo
select t1.col1 as [Key]
, t2.col1 as Value
from dbo.Table1 t1
join dbo.Table2 t2
on t1.id = t2.id
union all
select t1.col2
, t2.col2
from dbo.Table1 t1
join dbo.Table2 t2
on t1.id = t2.id
union all
select t1.col3
, t2.col3
from dbo.Table1 t1
join dbo.Table2 t2
on t1.id = t2.id