Making right joins and using STUFF - sql-server

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.

Related

Select values from Three tables value not in another table MSSQL

I am using SQL Database. I am having three tables like T1,T2,T3. I want to get a column values from a table by excluding the values exists in another table.
SELECT T3 THEN
SELECT T2 NOT in T3 THEN
SELECT T1 NOT in T3 and T2
CREATE TABLE T1(CID INT,NAME VARCHAR(100),EMAIL VARCHAR(50), MOIBLE VARCHAR(20))
CREATE TABLE T2(CID INT,NAME VARCHAR(100),EMAIL VARCHAR(50), MOIBLE VARCHAR(20))
CREATE TABLE T3(CID INT,NAME VARCHAR(100),EMAIL VARCHAR(50), MOIBLE VARCHAR(20))
Insert value
INSERT INTO T1 VALUES (1,'TEST1','a#gmail','123456')
INSERT INTO T1 VALUES (2,'TEST2','b#gmail','123456')
INSERT INTO T1 VALUES (3,'TEST3','c#gmail','123456')
INSERT INTO T1 VALUES (4,'TEST4','d#gmail','123456')
INSERT INTO T2 VALUES (1,'TEST1','updateda#gmail','123456')
INSERT INTO T2 VALUES (2,'TEST2','updatedb#gmail','77777')
INSERT INTO T3 VALUES (1,'TEST1','updateda#gmail','999999')
Expected output
SELECT T3 and
SELECT T2 record NOT in T3 and
SELECT T1 record NOT in T3 and T2
cid Name email moible
1 TEST1 updateda#gmail 999999 From T3
2 TEST2 updatedb#gmail 77777 From T2
3 TEST3 c#gmail 123456 From T1
4 TEST4 d#gmail 123456 From T1
I have written query for this
SELECT * FROM T2 where cid not in ( SELECT cid from T3)
UNION
SELECT * FROM T3
Here How to include T1 table?
You can add anther 1 union cid not in T2 and T3
SELECT * from T1 where cid not in(SELECT cid FROM T2 where cid not in ( SELECT
cid from T3)
UNION
SELECT cid FROM T3)
UNION
SELECT * FROM T2 where cid not in ( SELECT cid from T3)
UNION
SELECT * FROM T3

How to join 2 tables with inner and left outer join

I have two tables in MSSQL with the same structure T1 & T2. Both tables can INNER JOIN on Id but T2 may not contain the AccountId associated with the Id as in T1.
.
T1 Id AccountId Name T2 Id AccountId Name
111 5555 John 111 5555 John
122 5555 David 133 5555 Sharon
133 5555 Sharon
Below is the code I tried but the result is not working?.
.
INSERT INTO T3
SELECT T1.Id,T1.AccountId,T1.Name
FROM T1
INNER JOIN T2 T2.Id = T1.id
LEFT OUTER JOIN T1.AccountId = T2.AccountId
WHERE AccountId = 5555
The expected result would be to insert values that are not in T1 into T3
You need where clause:
INSERT INTO T3(Id, AccountId, Name)
SELECT T1.Id, T1.AccountId, T1.Name
FROM T1 LEFT JOIN
T2
ON T2.Id = T1.id
WHERE T2.AccountId IS NOT NULL;
Notes:
Only one LEFT JOIN is necessary. I don't know what the INNER JOIN is for.
Every JOIN should be followed by an ON clause.
You should list the columns when doing an INSERT.
You need the WHERE to find non-matches.
This query could also be written using NOT EXISTS.
This should be what you're after:
CREATE TABLE #T1 (id int, AccountId int, [Name] varchar(6));
CREATE TABLE #T2 (id int, AccountId int, [Name] varchar(6));
CREATE TABLE #T3 (id int, AccountId int, [Name] varchar(6));
INSERT INTO #T1
VALUES (111,5555,'John '),
(122,5555,'David '),
(133,5555,'Sharon');
INSERT INTO #T2
VALUES (111,5555,'John '),
(133,5555,'Sharon');
INSERT INTO #T3 (id, AccountId, [Name])
SELECT T1.id,
T1.AccountId,
T1.[Name]
FROM #T1 T1
LEFT JOIN #T2 T2 ON T1.ID = T2.id
WHERE T2.id IS NULL;
SELECT *
FROM #t3;
DROP TABLE #T1;
DROP TABLE #T2;
DROP TABLE #T3;

T-SQL - Compare two tables and display result as Available on Both, table1 only and table2 only

I have 2 tables and structure is same on both tables.
Table 1:
ID Name Phone
1 xxx 111
2 yyy 222
Table 2:
ID Name Phone
1 xxx 111
3 zzz 333
I need to compare these two tables and display the results (based on ID column- where condition ID) as
Available in both tables
Table1 only
Table2 only
This should be like this,
ID Name Phone Status
----------------------------------------
1 xxx 111 Available in both
2 yyy 222 Available in T1 only
3 zzz 333 Available in T2 only
using HASHBYTES :Demo Here ..you dont need to consume table mutiple times,but only once
;with cte
as
(
select id,name,phone,hashbytes('sha1',concat(id,name,phone) )as tb1
from #t1
)
select isnull(c.id,b.id) as id,
isnull(c.name,b.name) as name,
isnull(c.phone,b.phone) as phone,
case when c.tb1 is null then 'exists in second table only'
when c.tb1 is not null and b.tb1 is not null then 'exists in both'
when b.tb1 is null then 'exists in first table only'
end as 'exidts' from cte c
full join
(
select id,name,phone,hashbytes('sha1',concat(id,name,phone) )as tb1
from #t2
) b
on
b.tb1=c.tb1
Try this:
declare #table1 table
(
name varchar(10),
phone varchar(10)
)
declare #table2 table
(
name varchar(10),
phone varchar(10)
)
INSERT INTO #table1 VALUES('xxx','111')
INSERT INTO #table1 VALUES('yyy','222')
INSERT INTO #table2 VALUES('xxx','111')
INSERT INTO #table2 VALUES('zzz','333')
SELECT t1.name, t1.phone, 'Available on both' FROM
#table1 t1 INNER JOIN #table2 t2
ON t1.name = t2.name and t1.phone = t2.phone
UNION
SELECT name, phone, 'Available on T1 only' FROM
#table1 t1 WHERE NOT EXISTS
(SELECT 1 FROM #table2 t2
WHERE t1.name = t2.name and t1.phone = t2.phone)
UNION
SELECT name, phone, 'Available on T2 only' FROM
#table2 t2 WHERE NOT EXISTS
(SELECT 1 FROM #table1 t1
WHERE t1.name = t2.name and t1.phone = t2.phone)
You can use combination of FULL JOIN and IS NULL to check availability from both tables -
SELECT ISNULL(t1.id, t2.id) AS Id
, ISNULL(t1.name, t2.name) AS Name
, ISNULL(t1.phone, t2.phone) AS Phone
, CASE
WHEN t1.id IS NULL THEN 'Available in T2 only'
WHEN t2.id IS NULL THEN 'Available in T1 only'
ELSE 'Available in both'
END AS Status
FROM Table1 AS t1
FULL JOIN Table2 AS t2 ON (t2.id = t1.id);
As this query uses only one JOIN operation and no sub queries it is very fast.
This could work:
CREATE TABLE #T1 ( ID INT, Name VARCHAR(10), Phone VARCHAR(10) )
CREATE TABLE #T2 ( ID INT, Name VARCHAR(10), Phone VARCHAR(10) )
INSERT INTO #T1 VALUES ( 1, 'xxx', '111' ), ( 2, 'yyy', '222' )
INSERT INTO #T2 VALUES ( 1, 'xxx', '111' ), ( 3, 'zzz', '333' )
SELECT #T1.ID, #T1.Name, #T1.Phone, 'Available on both' AS Status
FROM #T1 INNER JOIN #T2 ON #T1.ID = #T2.ID
UNION
SELECT #T1.ID, #T1.Name, #T1.Phone, 'Available on T1 only' AS Status
FROM #T1 LEFT JOIN #T2 ON #T1.ID = #T2.ID
WHERE #T2.ID IS NULL
UNION
SELECT #T2.ID, #T2.Name, #T2.Phone, 'Available on T2 only' AS Status
FROM #T1 RIGHT JOIN #T2 ON #T1.ID = #T2.ID
WHERE #T1.ID IS NULL
DROP TABLE #T1
DROP TABLE #T2

How to join two Tables which have no unique ID

I am trying to Left join Table 1 to table 2
Table1 Table2
ID Data ID Data2
1 r 1 q
2 t 1 a
3 z 2 x
1 u 3 c
After i have left joined this two Tables i would like get something like this
Table1+2
ID Data Data2
1 r a
2 t x
3 z c
1 u q
and NOT
Table1+2
ID Data Data2
1 r q
2 t x
3 z c
1 u q
and my question is: is there any possibility to tell table 2 that if u have used something for table 1, dont use it and give me next value. do i have to make it im T-SQL or to and new column where i can list if this id exists then write 2 if not 1(Number data). How can i solve this problem?
Ty u in advance.
Since there's no uniqueness in the ID on both tables, lets add some uniqueness to it.
So it can be used to join on.
The window function ROW_NUMBER can be used for that.
An example solution that gives the expected result:
DECLARE #TestTable1 TABLE (ID INT, Data VARCHAR(1));
DECLARE #TestTable2 TABLE (ID INT, Data VARCHAR(1));
INSERT INTO #TestTable1 VALUES (1,'r'),(2,'t'),(3,'z'),(1,'u');
INSERT INTO #TestTable2 VALUES (1,'q'),(1,'a'),(2,'x'),(3,'c');
select
t1.ID, t1.Data,
t2.Data as Data2
from (
select ID, Data,
row_number() over (partition by ID order by Data) as rn
from #TestTable1
) t1
left join (
select ID, Data,
row_number() over (partition by ID order by Data) as rn
from #TestTable2
) t2 on t1.ID = t2.ID and t1.rn = t2.rn;
Note: Because of the LEFT JOIN, this does assume the amount of same ID's in table2 are equal or lower can those on table1. But you can change that to a FULL JOIN if that's not the case.
Returns :
ID Data Data2
1 r a
1 u q
2 t x
3 z c
To get the other result could have been achieved in different ways.
This is actually a more common situation.
Where one wants all from Table 1, but only get one value from Table 2 for each record of Table 1.
1) A top 1 with ties in combination with a order by rownumber()
select top 1 with ties
t1.ID, t1.Data,
t2.Data as Data2
from #TestTable1 t1
left join #TestTable2 t2 on t1.ID = t2.ID
order by row_number() over (partition by t1.ID, t1.Data order by t2.Data desc);
The top 1 with ties will only show those where the row_number() = 1
2) Using the row_number in a subquery:
select ID, Data, Data2
from (
select
t1.ID, t1.Data,
t2.Data as Data2,
row_number() over (partition by t1.ID, t1.Data order by t2.Data desc) as rn
from #TestTable1 t1
left join #TestTable2 t2 on t1.ID = t2.ID
) q
where rn = 1;
3) just a simple group by and a max :
select t1.ID, t1.Data, max(t2.Data) as Data2
from #TestTable1 t1
left join #TestTable2 t2 on t1.ID = t2.ID
group by t1.ID, t1.Data
order by 1,2;
All 3 give the same result:
ID Data Data2
1 r q
1 u q
2 t x
3 z c
Use ROW_NUMBER
DECLARE #Table1 TABLE (ID INT, DATA VARCHAR(10))
DECLARE #Table2 TABLE (ID INT, DATA VARCHAR(10))
INSERT INTO #Table1
VALUES
(1, 'r'),
(2, 't'),
(3, 'z'),
(1, 'u')
INSERT INTO #Table2
VALUES
(1, 'q'),
(1, 'a'),
(2, 'x'),
(3, 'c')
SELECT
A.*,
B.DATA
FROM
(SELECT *, ROW_NUMBER() OVER (PARTITION BY ID ORDER BY(SELECT NULL)) RowId FROM #Table1) A INNER JOIN
(SELECT *, ROW_NUMBER() OVER (PARTITION BY ID ORDER BY(SELECT NULL)) RowId FROM #Table2) B ON A.ID = B.ID AND
A.RowId = B.RowId

SQL Server- Table rows to data dictionary conversion

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

Resources