I have TWO tables
1) column
2) row
COLUMN TABLE
COLumnID
----------------
1
2
3
4
5
6
7
8
9
ROW TABLE
ROW iD
-------------
100
104
101
99
77
20
10
The final output should look like this:
01.Row 1 2 3 4 5 6 7 8 9
02.----------- ---- ---- ---- ---- ---- ---- ---- ---- ----
03.10 x x x
04.20 x x x x
05.77 x x
06.99 x x x
07.100 x x x x
08.101 x
09.104 x x x x
The challenge is to mark a coordinate, with a value of X, if and only if the row value is divisible by the col value, i.e. it has a modulo of zero. The additional requirements are: the final query must work with random row values and the pivot operator should be used.
The following should do what you are looking for in sql server.
use a CTE to determine where the x should be and then pivot from that CTE
with mq as(select a.rowid
,b.columnid
,case when (a.rowid % b.columnid) = 0 then 'X' else null end as coord
from row_table a
inner join column_table b on 1=1)
select rowid,[1], [2], [3], [4],[5], [6], [7], [8], [9]
from mq
pivot( max(coord) for columnid in ([1], [2], [3], [4],[5], [6], [7], [8], [9])) as pv
Related
We have this table:
Column A
Column B
01-01-2020
23
01-01-2020
24
01-01-2020
25
02-01-2020
11
02-01-2020
15
The requirement is to load the data in single row based on datetime column.
Column A
Column B
Column C
Column D
01-01-2020
23
24
25
02-01-2020
11
15
There can be up to 200 unique values against single datetime value.
How can this be achieved in a query?
I have tried using pivot but that results is aggregation which is not what I am after.
Since you have up to 200 hundred columns, I figured it would be best to number them. You can expand up to the required number of columns
Example
Select *
From (
Select [Column A]
,[Column B]
,RN = row_number() over (partition by [Column A] order by [Column B] )
From YourTable
) src
Pivot ( max([Column B]) for RN in ( [1], [2], [3], [4], [5], [6], [7], [8], [9],[10]
,[11],[12],[13],[14],[15],[16],[17],[18],[19],[20]
,[21],[22],[23],[24],[25],[26],[27],[28],[29],[30]
) ) Pvt
Preface: this isn't homework - I am learning SQL.
I was given the problem to make a multiplication chart.
Here's my solution:
create table x (x int)
create table y ([1] int, [2] int, [3] int, [4] int, [5] int, [6] int, [7] int, [8] int, [9] int, [10] int)
insert into x (x)
values ('1')
insert into x (x)
values ('2')
insert into x (x)
values ('3')
insert into x (x)
values ('4')
insert into x (x)
values ('5')
insert into x (x)
values ('6')
insert into x (x)
values ('7')
insert into x (x)
values ('8')
insert into x (x)
values ('9')
insert into x (x)
values ('10')
insert into y ([1], [2], [3], [4], [5], [6], [7], [8], [9], [10])
values ('1', '2', '3', '4', '5', '6', '7', '8', '9', '10')
select * from x
select * from y
select x * y.[1] as [1's table],
x * y.[2] as [2's table],
x * y.[3] as [3's table],
x * y.[4] as [4's table],
x * y.[5] as [5's table],
x * y.[6] as [6's table],
x * y.[7] as [7's table],
x * y.[8] as [8's table],
x * y.[9] as [9's table],
x * y.[10] as [10's table]
from x cross join y
This all seems very messy and typing it out was a bit tedious. I wanted to try to do it without having to specify each column in the y table as so:
select x * y from x, y
But this didn't work as SQL is asking for a column. But I want it to perform multiplication across all columns. How do I make my times table more efficiently?
Unfortunately there is no built-in "give me all the numbers from 1-n" (never mind "give me all of 1-n times 1-n") - but we can build it manually using a recursive CTE cross applied to each value in the set:
; -- see sqlblog.org/cte
WITH n(n) AS (SELECT 1 UNION ALL SELECT n+1 FROM n WHERE n < 10)
SELECT src = QUOTENAME(n.n), p.* FROM n CROSS APPLY
(VALUES(n.n*1,n.n*2,n.n*3,n.n*4,n.n*5,n.n*6,n.n*7,n.n*8,n.n*9,n.n*10))
AS p([* 1],[* 2],[* 3],[* 4],[* 5],[* 6],[* 7],[* 8],[* 9],[* 10]);
Output:
src
* 1
* 2
* 3
* 4
* 5
* 6
* 7
* 8
* 9
* 10
[1]
1
2
3
4
5
6
7
8
9
10
[2]
2
4
6
8
10
12
14
16
18
20
[3]
3
6
9
12
15
18
21
24
27
30
[4]
4
8
12
16
20
24
28
32
36
40
[5]
5
10
15
20
25
30
35
40
45
50
[6]
6
12
18
24
30
36
42
48
54
60
[7]
7
14
21
28
35
42
49
56
63
70
[8]
8
16
24
32
40
48
56
64
72
80
[9]
9
18
27
36
45
54
63
72
81
90
[10]
10
20
30
40
50
60
70
80
90
100
Example db<>fiddle
Arguably, that's not much better than your original attempt, because you still have to hard-code a bunch of sequential numbers, and that isn't fun.
With a little more effort you can build this so it can construct the table dynamically, for any upper bound (within reason - if you go beyond 100 you'll need to add OPTION (MAXRECURSION)), and without you hardcoding any number except defining the single upper bound value (note this part of the solution assumes SQL Server 2017 or better):
DECLARE #TimesTableUpperBound int = 15;
DECLARE #cols nvarchar(max) = N'',
#piv nvarchar(max) = N'',
#sql nvarchar(max) = N';WITH n(n) AS
(SELECT 1 UNION ALL SELECT n+1 FROM n WHERE n < #ub)
SELECT src = QUOTENAME(n.n), p.* FROM n CROSS APPLY
(VALUES(';
; -- see sqlblog.org/cte
WITH n(n) AS (SELECT 1 UNION ALL SELECT n+1
FROM n WHERE n < #TimesTableUpperBound)
SELECT #cols = STRING_AGG(CONCAT('n.n*',n),','),
#piv = STRING_AGG(QUOTENAME(CONCAT('* ',n)),',')
FROM n;
SELECT #sql += #cols + N'))
AS p(' + #piv + ');';
SELECT #sql;
EXEC sys.sp_executesql #sql, N'#ub int', #TimesTableUpperBound;
I'm not going to copy the output here but you can play with any positive integer for upper bound here:
Example db<>fiddle
That isn't that much fun either, but you can tuck that away in a stored procedure, and any time you need a multiplication table, you don't have to remember how to build recursive CTEs or string aggregation or dynamic SQL, you just call:
EXEC dbo.BuildMyNumbersTimesTable #TimesTableUpperBound = 32;
I am using SQL Server 2008 and would like to transform my data such that:
Dataset:
ID Item Columns Result
1 1 X A
2 1 Y B
3 1 Z C
4 2 X D
5 2 Y E
6 2 Z NULL
7 3 X F
8 3 Y G
9 3 Z H
Results Desired:
Item X Y Z
1 A B C
2 D E NULL
3 F G H
At this time, I am doing the following, then pasting the columns I need into Excel:
Select * from thisTable where Column=X
Select * from thisTable where Column=Y
Select * from thisTable where Column=Z
However, not all of the rows match up to can can't just smack the tables side by side. For columns without a Result, I'd like NULL to show up to fill in the rows to make them all the same number of records.
I looked up PIVOT but I don't think this works here...what is this type of data transformation called? I don't think it's a crosstab...
Thanks!
You can do a crosstab using conditional aggregation:
SELECT
Item,
[X] = MAX(CASE WHEN [Columns] = 'X' THEN Result END),
[Y] = MAX(CASE WHEN [Columns] = 'Y' THEN Result END),
[Z] = MAX(CASE WHEN [Columns] = 'Z' THEN Result END)
FROM thisTable
GROUP BY Item
use PIVOT
select *
from (
select Item, Columns, Result
from thisTable
) t
pivot (
max (Result)
for Columns in (X, Y, Z)
) p
I realise this maybe similar to other questions, but I am stuck!
I am having trouble organising some data into an appropriate format to export to another tool. Basically I have an ID column and then 2 response columns. I would like to separate the ID and then list the responses under each. See the example below for clarification.
I have played around with Pivot and UnPivot but can't get it quite right.
Here is how the data looks now.
ID X1 X2
1 2 Y
1 5 Y
1 3 N
1 7 N
1 6 Y
2 5 N
2 4 Y
2 8 Y
2 3 N
3 5 Y
3 1 N
3 9 N
Here is how I would like the data to look
ID1_X1 ID1_X2 ID2_X1 ID2_X2 ID3_X1 ID3_X2
2 Y 5 N 5 Y
5 Y 4 Y 1 N
3 N 8 Y 9 N
7 N 3 N null null
6 Y null null null null
Here is the code to create/populate the table.
create table #test (ID int, X1 int, X2 varchar(1))
insert into #test values
('1','2','Y'),('1','5','Y'),('1','3','N'),('1','7','N'),
('1','6','Y'),('2','5','N'),('2','4','Y'),('2','8','Y'),
('2','3','N'),('3','5','Y'),('3','1','N'),('3','9','N')
You can do this using aggregation and row_number() . . . assuming you know the ids in advance:
select max(case when id = 1 then x1 end) as x1_1,
max(case when id = 1 then x2 end) as x2_1,
max(case when id = 2 then x1 end) as x1_2,
max(case when id = 2 then x2 end) as x2_2,
max(case when id = 3 then x1 end) as x1_3,
max(case when id = 3 then x2 end) as x2_3
from (select t.*,
row_number() over (partition by id order by (select null)) a seqnum
from #test t
) t
group by seqnum;
I should note that SQL tables represent unordered sets. Your original data doesn't have an indication of the ordering, so this is not guaranteed to put the values in the same order as the original data (actually, there is no such order that that statement is a tautology). If you have another column with the ordering, then you can use that.
Here is a alternative approach to Gordan's good answer using OUTER JOIN's
Considering that there is a Identity column in your table to define the order of X1 in each ID and fixed number of ID's
;WITH FST
AS (SELECT ROW_NUMBER()OVER(ORDER BY IDENTITY_COL) RN,X1 AS ID1_X1,X2 AS ID1_X2
FROM #TEST A
WHERE ID = 1),
SCD
AS (SELECT ROW_NUMBER()OVER(ORDER BY IDENTITY_COL) RN,X1 AS ID2_X1,X2 AS ID2_X2
FROM #TEST A
WHERE ID = 2),
TRD
AS (SELECT ROW_NUMBER()OVER(ORDER BY IDENTITY_COL) RN,X1 AS ID3_X1,X2 AS ID3_X2
FROM #TEST A
WHERE ID = 3)
SELECT ID1_X1,ID1_X2,ID2_X1,ID2_X2,ID3_X1,ID3_X2
FROM FST A
FULL OUTER JOIN SCD B
ON A.RN = B.RN
FULL OUTER JOIN TRD C
ON C.RN = COALESCE(B.RN, A.RN)
This is my query
SELECT CAL.CALENDAR_NAME,CAL.CALENDAR_ID,CALDAY.CALENDARDAY_DAYID
FROM lms_calendar AS CAL
LEFT JOIN LMS_CALENDARDAY AS CALDAY
ON CAL.CALENDAR_ID = CALDAY.CALENDARDAY_CALENDARID
and I get results like this
CALENDAR_NAME CALENDAR_ID CALENDARDAY_DAYID
-------------------------------------------------- ----------- -----------------
Test 1 1
Test 1 2
Test 1 3
Test 1 4
Test 1 6
But I need like this
calendar_name calendar_dayid calendar_dayid calendar_dayid calendar_dayid calendar_dayid
test 1 2 3 4
Here is a query that uses the PIVOT operator
SELECT calendar_name,
[1] AS calendar_dayid,
[2] AS calendar_dayid,
[3] AS calendar_dayid,
[4] AS calendar_dayid,
[5] AS calendar_dayid
FROM (
SELECT CAL.CALENDAR_NAME,CAL.CALENDAR_ID,CALDAY.CALENDARDAY_DAYID
FROM lms_calendar AS CAL
LEFT JOIN LMS_CALENDARDAY AS CALDAY
ON CAL.CALENDAR_ID = CALDAY.CALENDARDAY_CALENDARID
) AS src
PIVOT (
MAX(calendarday_dayid)
FOR calendarday_dayid IN ([1], [2], [3], [4], [5])
) AS pvt