SQL joined table pivot without aggregate - sql-server

I have two tables:
Table1
ID TYPE
1 ABC1
2 ABC2
3 ABC3
Table2
ID Data
1 100
1 101
2 10
2 90
And I want the results to look like this:
ID Data1 Data2
1 100 101
2 10 90
But I'm having a total mare with my attempts at creating the pivot. So far I have:
With Inital_Data As (
Select
A.ID,
B.Data As Data1,
B.Data As Data2
From
Table1 A join
Table2 B on
A.ID = B.ID
)
Select *
From
Initial_Data
PIVOT
(Max(ID) FOR Data IN (Data1,Data2)) p
I know this is rubbish but so far even the logic of what I'm trying to achieve is escaping me, let alone the syntax! Can anyone give me a guiding hand?

Pivot with more than one column needs some tricks, I prefer the XML concatenation. First I take all values for each ID in only one XML, then you can take these values one by one:
Just paste this into an empty query window and execute. Adapt for your needs
EDIT: Includes column Type from TABLE1 as Caption for ID...
DECLARE #Table1 TABLE(ID INT,[TYPE] VARCHAR(10));
INSERT INTO #Table1 VALUES
(1,'ABC1')
,(2,'ABC2')
,(3,'ABC3');
DECLARE #Table2 TABLE(ID INT,DATA INT);
INSERT INTO #Table2 VALUES
(1,100)
,(1,101)
,(2,10)
,(2,90);
WITH DistinctIDs AS
(
SELECT DISTINCT tbl2.ID,tbl1.[TYPE]
FROM #Table2 AS tbl2
INNER JOIN #Table1 AS tbl1 ON tbl1.ID=tbl2.ID
)
SELECT ID,[TYPE]
,concatXML.x.value('/root[1]/item[1]/#data','int') AS Data1
,concatXML.x.value('/root[1]/item[2]/#data','int') AS Data2
FROM DistinctIDs AS dIDs
CROSS APPLY
(
SELECT ID AS [#id],DATA AS [#data]
FROM #Table2 AS tbl WHERE tbl.ID=dIDs.ID
FOR XML PATH('item'), ROOT('root'),TYPE
) AS concatXML(x)

Related

SQL Server : add a new column using union

I have 2 tables which have 2 columns in common and 1 column is different in both table
Table A
Table B
I need to create a common table having the values as follows
Expected Output
I tried using join on Memid and Meas but it duplicates as the 2 field do not create unique set as shown in figure
I tried union but then I get a resultset like this
Output for Inner join with distinct condition
How do I go about achieving the desired result set?
Note: Just a note coincidentally in this case the 2 columns seems to have similar values but they can be different.
Basically I need to create this one table with the 4 columns where Payer and PPayer columns should be independent of each other.
You don't need to use UNION, you can try like following using INNER JOIN.
INSERT INTO NewTable (
UserId
,DEPT
,ROOM
,LAB
)
SELECT DISTINCT ta.UserId
,ta.DEPT
,ta.ROOM
,tb.LAB
FROM TableA ta
INNER JOIN TableB tb ON ta.UserId = tb.UserId
AND ta.DEPT = tb.DEPT
Check Working Demo
Shanawaz Khan, Try this Solution
Declare Sample Table
DECLARE #A as TABLE(
UserId INT,
DEPT VARCHAR(50),
ROOM INT)
DECLARE #B as TABLE(
UserId INT,
DEPT VARCHAR(50),
LAB VARCHAR(50))
Insert Sample Records in Created Table
INSERT INTO #A (UserId,DEPT,ROOM) VALUES(1,'A',1),(1,'B',1),(1,'A',2),(1,'B',2)
INSERT INTO #B (UserId,DEPT,LAB) VALUES(1,'A','P'),(1,'B','Q'),(1,'A','P'),(1,'B','Q')
Generate DEPT wise Row number for Both Tables and Insert into another Temptable
SELECT ROW_NUMBER() OVER(PARTITION BY A.DEPT ORDER BY A.ROOM ) AS Rno,* INTO #tbl_A FROM #A A
SELECT ROW_NUMBER() OVER(PARTITION BY B.DEPT ORDER BY B.LAB) AS Rno,* INTO #tbl_B FROM #B B
Final Query Using Inner Join
SELECT A.UserId,A.DEPT,A.ROOM,B.LAB FROM #tbl_A AS A
INNER JOIN #tbl_B AS B ON A.Rno =B.Rno AND A.DEPT =B.DEPT ORDER BY A.ROOM, B.DEPT
Drop Created Temptable
DROP TABLE #tbl_A,#tbl_B
OutPut

Combine two tables into one table with separated values

This is a simple rather simple question, but for whatever reason I just can't get to a solution.
How do I join the two tables like such that I have get NULL values like this?
Table #T1
A
--
1
2
Table #T2
B
--
3
Desired result:
A B
----
1 NULL
2 NULL
NULL 3
EDIT:
My solution was this
SELECT #T1.A, #T2.B
FROM #t2
RIGHT JOIN #T1 ON 1 = 0
UNION
SELECT #T1.A, #T2.B
FROM #t2
LEFT JOIN #t1 ON 1 = 0
But it seems overly complicated. Anything better?
Use FULL JOIN
select *
from #t1 t1
full outer join #t2 t2 on t1.a = t2.b
or use UNION ALL
select a,Null as b
from #t1
union all
select NULL, b
from #t2
since there is no common records in both the tables, both the query results will look same. When there is a common record, the result will differ. Use the one that suits your requirement
This is the better/simple one
SELECT #T1.A, #T2.B
FROM #t2
FULL OUTER JOIN #T1 ON 1 = 0

MSSQL SP: Select all rows from one table using IDs from another

Perhaps quite a simple question, that seems to have a rather complicated answer that I have not been able to dig out.
Im using an SQL-server 2012.
I have these two statements, that selects all my data based on a parameter, and then also selects up to five rows of data (which means no joins) from another table based on the IDs gotten from the first select.
SELECT * FROM TBL1 WHERE XXX
SELECT * FROM TBL2
WHERE TBL1_ID IN (SELECT ID FROM TBL1 WHERE XXX)
It seems very redundant to me, that I basicly have to repeat my TBL1 select in my TBL2, and instead I would like to know if I can select from TBL2 using the ID's from the * data I got from TBL1.
I am fully aware that this will most likely result in two resultsets that dont necessarily correlate, but I can generally use PHP array-manipulation to fix this so its not that big of a deal.
You also use EXISTS
SELECT * FROM TBL2
WHERE EXISTS (SELECT 1 FROM TBL1 WHERE TBL1.ID = TBL2.TBL1_ID AND XXX)
Using IN:
Declare #T1 table (ID INT , Value VARCHAR(50) );
Declare #T2 table (ID INT);
INSERT INTO #T1 Values (1,'First') , (2,'Second');
INSERT INTO #T2 Values (1),(3);
SELECT * FROM #T1 WHERE ID IN (SELECT ID FROM #T2);
Resault :
ID Value
----------- ------------------------------------------------------------------------------
1 First
Using INNER JOIN :
SELECT T1.ID , T1.Value FROM #T1 T1 INNER JOIN #T2 T2 ON T1.ID = T2.ID;
Resault:
ID Value
----------- ------------------------------------------------------------------------------
1 First
Using LEFT JOIN :
SELECT T1.ID , T1.Value FROM #T1 T1 LEFT JOIN #T2 T2 ON T1.ID = T2.ID
WHERE T2.ID IS NOT NULL;
Resault :
ID Value
----------- -------------------------------------------------------------------------------
1 First

SQL Server: How to select top rows of a group based on value of the column of that group?

I have two tables like below.
table 1
id rem
1 2
2 1
table 2
id value
1 abc
1 xyz
1 mno
2 mnk
2 mjd
EDIT:
#output
id value
1 abc
1 xyz
2 mnk
What i want to do is select top 2 rows of table2 with id one as rem value is 2 for id 1 and top 1 row with id 2 as its rem value is 1 and so on. I am using MS sqlserver 2012 My whole scenario is more complex than this. Please help.
Thank you.
EDIT : I know that i should have given what i have done and how i am doing it but for this particular part i don't have idea for starting. I could do this by using while loop for each unique id but i want to do it in one go if possible.
First, SQL tables represent unordered sets. There is no specification of which values you get, unless you include an order by.
For this purpose, I would go with row_number():
select t2.*
from table1 t1 join
(select t2.*,
row_number() over (partition by id order by id) as seqnum
from table2 t2
) t2
on t1.id = t2.id and t2.seqnum <= t1.rem;
Note: The order by id in the windows clause should be based on which rows you want. If you don't care which rows, then order by id or order by (select null) is fine.
Try This:
DECLARE #tbl1 TABLE (id INT, rem INT)
INSERT INTO #tbl1 VALUES (1, 2), (2, 1)
DECLARE #tbl2 TABLE (id INT, value VARCHAR(10))
INSERT INTO #tbl2 VALUES (1, 'abc'), (1, 'xyz'),
(1, 'mno'), (2, 'mnk'), (2, 'mjd')
SELECT * FROM #tbl1 -- your table 1
SELECT * FROM #tbl2 -- your table 2
SELECT id,value,rem FROM ( SELECT ROW_NUMBER() OVER (PARTITION BY T.ID ORDER BY T.ID) rowid,
T.id,T.value,F.rem FROM #tbl2 T LEFT JOIN #tbl1 F ON T.id = F.id ) A WHERE rowid = 1
-- your required output
Hope it helps.

Combine multiple results in a subquery into a single comma-separated value

I've got two tables:
TableA
------
ID,
Name
TableB
------
ID,
SomeColumn,
TableA_ID (FK for TableA)
The relationship is one row of TableA - many of TableB.
Now, I want to see a result like this:
ID Name SomeColumn
1. ABC X, Y, Z (these are three different rows)
2. MNO R, S
This won't work (multiple results in a subquery):
SELECT ID,
Name,
(SELECT SomeColumn FROM TableB WHERE F_ID=TableA.ID)
FROM TableA
This is a trivial problem if I do the processing on the client side. But this will mean I will have to run X queries on every page, where X is the number of results of TableA.
Note that I can't simply do a GROUP BY or something similar, as it will return multiple results for rows of TableA.
I'm not sure if a UDF, utilizing COALESCE or something similar might work?
Even this will serve the purpose
Sample data
declare #t table(id int, name varchar(20),somecolumn varchar(MAX))
insert into #t
select 1,'ABC','X' union all
select 1,'ABC','Y' union all
select 1,'ABC','Z' union all
select 2,'MNO','R' union all
select 2,'MNO','S'
Query:
SELECT ID,Name,
STUFF((SELECT ',' + CAST(T2.SomeColumn AS VARCHAR(MAX))
FROM #T T2 WHERE T1.id = T2.id AND T1.name = T2.name
FOR XML PATH('')),1,1,'') SOMECOLUMN
FROM #T T1
GROUP BY id,Name
Output:
ID Name SomeColumn
1 ABC X,Y,Z
2 MNO R,S
1. Create the UDF:
CREATE FUNCTION CombineValues
(
#FK_ID INT -- The foreign key from TableA which is used
-- to fetch corresponding records
)
RETURNS VARCHAR(8000)
AS
BEGIN
DECLARE #SomeColumnList VARCHAR(8000);
SELECT #SomeColumnList =
COALESCE(#SomeColumnList + ', ', '') + CAST(SomeColumn AS varchar(20))
FROM TableB C
WHERE C.FK_ID = #FK_ID;
RETURN
(
SELECT #SomeColumnList
)
END
2. Use in subquery:
SELECT ID, Name, dbo.CombineValues(FK_ID) FROM TableA
3. If you are using stored procedure you can do like this:
CREATE PROCEDURE GetCombinedValues
#FK_ID int
As
BEGIN
DECLARE #SomeColumnList VARCHAR(800)
SELECT #SomeColumnList =
COALESCE(#SomeColumnList + ', ', '') + CAST(SomeColumn AS varchar(20))
FROM TableB
WHERE FK_ID = #FK_ID
Select *, #SomeColumnList as SelectedIds
FROM
TableA
WHERE
FK_ID = #FK_ID
END
In MySQL there is a group_concat function that will return what you're asking for.
SELECT TableA.ID, TableA.Name, group_concat(TableB.SomeColumn)
as SomColumnGroup FROM TableA LEFT JOIN TableB ON
TableB.TableA_ID = TableA.ID
I think you are on the right track with COALESCE. See here for an example of building a comma-delimited string:
http://www.sqlteam.com/article/using-coalesce-to-build-comma-delimited-string
You may need to provide some more details for a more precise response.
Since your dataset seems kind of narrow, you might consider just using a row per result and performing the post-processing at the client.
So if you are really looking to make the server do the work return a result set like
ID Name SomeColumn
1 ABC X
1 ABC Y
1 ABC Z
2 MNO R
2 MNO S
which of course is a simple INNER JOIN on ID
Once you have the resultset back at the client, maintain a variable called CurrentName and use that as a trigger when to stop collecting SomeColumn into the useful thing you want it to do.
Assuming you only have WHERE clauses on table A create a stored procedure thus:
SELECT Id, Name From tableA WHERE ...
SELECT tableA.Id AS ParentId, Somecolumn
FROM tableA INNER JOIN tableB on TableA.Id = TableB.F_Id
WHERE ...
Then fill a DataSet ds with it. Then
ds.Relations.Add("foo", ds.Tables[0].Columns("Id"), ds.Tables[1].Columns("ParentId"));
Finally you can add a repeater in the page that puts the commas for every line
<asp:DataList ID="Subcategories" DataKeyField="ParentCatId"
DataSource='<%# Container.DataItem.CreateChildView("foo") %>' RepeatColumns="1"
RepeatDirection="Horizontal" ItemStyle-HorizontalAlign="left" ItemStyle-VerticalAlign="top"
runat="server" >
In this way you will do it client side but with only one query, passing minimal data between database and frontend
I tried the solution priyanka.sarkar mentioned and the didn't quite get it working as the OP asked. Here's the solution I ended up with:
SELECT ID,
SUBSTRING((
SELECT ',' + T2.SomeColumn
FROM #T T2
WHERE WHERE T1.id = T2.id
FOR XML PATH('')), 2, 1000000)
FROM #T T1
GROUP BY ID
Solution below:
SELECT GROUP_CONCAT(field_attr_best_weekday_value)as RAVI
FROM content_field_attr_best_weekday LEFT JOIN content_type_attraction
on content_field_attr_best_weekday.nid = content_type_attraction.nid
GROUP BY content_field_attr_best_weekday.nid
Use this, you also can change the Joins
SELECT t.ID,
t.NAME,
(SELECT t1.SOMECOLUMN
FROM TABLEB t1
WHERE t1.F_ID = T.TABLEA.ID)
FROM TABLEA t;
This will work for selecting from different table using sub query.
I have reviewed all the answers. I think in database insertion should be like:
ID Name SomeColumn
1. ABC ,X,Y Z (these are three different rows)
2. MNO ,R,S
The comma should be at previous end and do searching by like %,X,%

Resources