How do i convert rows into columns? - sql

i know this can be done with pivot but dont know how to put this in query..heres my table..
Id Date Code
1 1-2-2011 Code1
2 2-2-2011 Code2
Desired table:
Id 1-2-2011 2-2-2011
1 Code1 Null
2 Null Code2
Heres something i am trying but i want to know if there is any different way..
SELECT [Id], '1-2-2011','2-2-2011'
FROM ( SELECT [Id]
, Code
FROM #r
) p PIVOT ( Code
FOR [date] IN ('1-2-2011','2-2-2011')
) AS pvt
ORDER BY [Id]

The correct PIVOT query would be something like this
declare #r table (Mobile int, Calldate datetime, Dispo varchar(10))
insert #r select
1, '2011-02-21', 'Code1' union all select
2, '2011-02-22', 'Code2'
SELECT ID, [2011-02-21], [2011-02-22]
-- SELECT * << or just use this, which includes all columns
FROM (
SELECT Id, Date, Code
FROM #r) p
PIVOT (MAX(Code) FOR Date IN ([2011-02-21], [2011-02-22])) AS pvt
ORDER BY ID
Your query used
SELECT [Id], '1-2-2011','2-2-2011'
Which includes two FIXED-VALUE strings, which means the DATA is the string '1-2-2011', not a column name. You also needed MAX(Code) or some aggregate function to use when pivoting.
Pivoting in SQL Server requires you to know the columns in advances, which you need to list out in the FOR () bit. Otherwise, you will need to look at dynamic pivoting. This is true whether you use the PIVOT operator or the MAX(CASE pattern to pivot.
The MAX(CASE) pattern
select id,
MAX(case when date = '2011-02-21' then Code end) "2011-02-21",
MAX(case when date = '2011-02-22' then Code end) "2011-02-22"
from #r
group by id

Related

How to ROWCOUNT_BIG() value with union all

I have the following query in SQL Server. How do I get the number of rows of previous select query as following format?
Sample Query
select ID, Name FROM Branch
UNION ALL
SELECT ROWCOUNT_BIG(), ''
Sample Output
If you use a CTE you can count the rows and union all together:
with cte as (
select ID, [Name]
from dbo.Branch
)
select ID, [Name]
from cte
union all
select count(*) + 1, ''
from cte;
I think you want to see total count of the select statement. you can do this way.
CREATE TABLE #test (id int)
insert into #test(id)
SELECT 1
SELECT id from #test
union all
SELECT rowcount_big()
Note: Here, the ID will be implicitly converted to BIGINT datatype, based on the datatype precedence. Read more
Presumably, you are running this in some sort of application. So why not use ##ROWCOUNT?
select id, name
from . . .;
select ##rowcount_big; -- big if you want a bigint
I don't see value to including the value in the same query. However, if the underlying query is an aggregation query, there might be a way to do this using GROUPING SETS.
Here are two ways. It's better to use a CTE to define the row set so further table inserts don't interfere with the count. Since you're using ROWCOUNT_BIG() these queries use COUNT_BIG() (which also returns bigint) to count the inserted rows. In order to make sure the total always appears as the last row an 'order_num' column was added to the SELECT list and ORDER BY clause.
drop table if exists #tTest;
go
create table #tTest(
ID int not null,
[Name] varchar(10) not null);
insert into #tTest values
(115, 'Joe'),
(116, 'Jon'),
(117, 'Ron');
/* better to use a CTE to define the row set */
with t_cte as (
select *
from #tTest)
select 1 as order_num, ID, [Name]
from t_cte
union all
select 2 as order_num, count_big(*), ''
from t_cte
order by order_num, ID;
/* 2 separate queries could give inconsistent result if table is inserted into */
select 1 as order_num, ID, [Name]
from #tTest
union all
select 2 as order_num, count_big(*), ''
from #tTest
order by order_num, ID;
Both return
order_num ID Name
1 115 Joe
1 116 Jon
1 117 Ron
2 3

Auto increment the column value by 1 conditionally in select query in sql

I am having input table like below:
and in a select query without alteration of table need an output like:
drop table if exists T;
create table T(id int, nm nvarchar(10))
GO
insert T(id, nm) values (1,'r'),(2,'r'),(3,null),(4,'r')
SELECT * FROM T
GO
-- solution:
select
id, nm,
CASE WHEN nm is not null then count(nm) over (order by id) ELSE NULL END
from T
GO
compare execution plan of all solutions (using SQL 2017) :-)
My solution 21%; LukStorms solution 38%; Ian-Fogelman solution 41%
Choose your solution after you test in your specific server!
You can calculate a row_number partitioned on whether "nm" is null, then only show the calculated row_number when "nm" is not null.
Example snippet:
declare #T table (id int identity(1,1) primary key, nm varchar(8));
insert into #T (nm) values ('R'),('R'),(null),('R');
select *,
iif(nm is null,null,row_number() over (partition by iif(nm is null,1,0) order by id)) as [Count]
from #T
order by id
;WITH CTE AS
(
SELECT ID,
ROW_NUMBER() OVER(PARTITION BY 1 ORDER BY ID) AS [COUNT]
FROM [TABLE] WHERE NM IS NOT NULL
)
SELECT S.ID,
S.NM,
CTE.[COUNT]
FROM [TABLE] AS S LEFT JOIN CTE AS CTE ON S.ID = CTE.ID
You can start with a CTE that adds a ROW_NUMBER() column and filters out rows WHERE 'nm' IS NULL.
Then SELECT from your table and OUTER JOIN to the CTE, using the ROW_NUMBER column to populate your Count column.

Conditional Selection of Rows Using TSQL SQL Server (2008 R2)

I've been staring at this for hours and hours and can't come up with an "elegant" set-based way of getting the result set I need...
Here's my sample data (my real data could be 1,000,000+ rows)...
DECLARE #t AS TABLE (ID int,ID1 nvarchar(15),[DATE] date,PERIOD int,[TYPE] nchar(1));
INSERT INTO #t (ID,ID1,[DATE],PERIOD,[TYPE])
VALUES
(1,N'NUM1','2016-01-01',1,N'B'),
(2,N'NUM1','2016-01-01',2,N'A'),
(3,N'NUM1','2016-01-01',3,N'A'),
(4,N'NUM1','2016-01-01',4,N'B'),
(5,N'NUM1','2016-01-01',4,N'A'),
(6,N'NUM1','2016-01-01',5,N'A'),
(7,N'NUM1','2016-01-02',1,N'A'),
(8,N'NUM1','2016-01-02',2,N'A'),
(9,N'NUM1','2016-01-02',3,N'A'),
(10,N'NUM1','2016-01-02',4,N'A'),
(11,N'NUM1','2016-01-02',5,N'A'),
(12,N'NUM2','2016-01-01',1,N'A'),
(13,N'NUM2','2016-01-01',1,N'B'),
(14,N'NUM2','2016-01-01',2,N'A'),
(15,N'NUM2','2016-01-01',3,N'A'),
(16,N'NUM2','2016-01-01',4,N'B'),
(17,N'NUM2','2016-01-01',4,N'A'),
(18,N'NUM2','2016-01-01',5,N'A'),
(19,N'NUM2','2016-01-02',1,N'A'),
(20,N'NUM2','2016-01-02',2,N'B'),
(21,N'NUM2','2016-01-02',3,N'A'),
(22,N'NUM2','2016-01-02',4,N'A'),
(23,N'NUM2','2016-01-02',4,N'B'),
(24,N'NUM2','2016-01-02',5,N'A');
Here is the result set I'm trying to get...
1,'NUM1','2016-01-01',1,'B'
2,'NUM1','2016-01-01',2,'A'
3,'NUM1','2016-01-01',3,'A'
5,'NUM1','2016-01-01',4,'A'
6,'NUM1','2016-01-01',5,'A'
7,'NUM1','2016-01-02',1,'A'
8,'NUM1','2016-01-02',2,'A'
9,'NUM1','2016-01-02',3,'A'
10,'NUM1','2016-01-02',4,'A'
11,'NUM1','2016-01-02',5,'A'
12,'NUM2','2016-01-01',1,'A'
14,'NUM2','2016-01-01',2,'A'
15,'NUM2','2016-01-01',3,'A'
17,'NUM2','2016-01-01',4,'A'
18,'NUM2','2016-01-01',5,'A'
19,'NUM2','2016-01-02',1,'A'
20,'NUM2','2016-01-02',2,'B'
21,'NUM2','2016-01-02',3,'A'
22,'NUM2','2016-01-02',4,'A'
24,'NUM2','2016-01-02',5,'A'
Simply put, each day has 5 periods. They can be of type A or B. I need to get the A types. but if there are no A types, I need to get the B types... (Sounds so simple when I write it out.., but my brain will not come up with something suitable)
Pleeeeeease put me out of my misery..
You can use ROW_NUMBER for this:
SELECT ID, ID1, [DATE], PERIOD, [TYPE]
FROM (
SELECT ID, ID1, [DATE], PERIOD, [TYPE],
ROW_NUMBER() OVER (PARTITION BY ID1, [DATE], PERIOD
ORDER BY [TYPE]) AS rn
FROM #t) AS t
WHERE t.rn = 1
Using ORDER BY [TYPE] in the OVER clause of ROW_NUMBER places 'A' records on top of 'B' records. If there are no 'A' records for a given ID1, [DATE], PERIOD then B records are assigned rn = 1.
Your desired outpout contradicts the statement that "I need to get the A types. but if there are no A types, I need to get the B types... ". Every date in the data has one or more 'A' types. By the statement, the output should include only the 'A' types. But if the statement is correct, then this should work:
Select d.[DATE], t.Id, t.ID1, t.PERIOD, t.[TYPE]
from (select distinct [date] from #t) d
left join #t t
on t.[date] = d.[date]
and t.type = case when exists
(select * from #t
where [date] = d.[Date]
and type = 'A') then 'A'
else 'B' End
I've just come up with
SELECT * FROM #t WHERE [TYPE]='A'
UNION ALL
SELECT * FROM #t t1 WHERE [TYPE]='B' AND NOT EXISTS (SELECT ID FROM #t WHERE ID1=t1.ID1 AND [TYPE]='A' AND [DATE]=t1.[DATE] AND Period=t1.Period)
ORDER BY ID;
which give's me what I need...

PK Field Does Not Allow Pivot to Display as 1 Record

I am trying to Pivot a table and display the results in 1 record. This all works if there is no PK field , but there is one and I am not getting the desired result. You can use the statement below to Test.
Create table #Test
(id int identity(1,1), item_name varchar(50),item_value varchar(50), decode float )
insert into #Test (item_name, item_value, decode)
values ('Threshold', 'GROWTH', 0.6),
('Threshold', 'LEVERAGE', 0.4)
Select pvt.* from #Test d
Pivot (
max(d.decode)
for d.item_value in (Growth,Leverage)
) as pvt
where item_name = 'Threshold'
drop table #test
The Results of this Query are
| id | item_name | Growth | Leverage
1 Threshold 0.6 NULL
2 Threshold NULL 0.4
My Desired Results are
item_name | Growth | Leverage
Threshold 0.6 0.4
If you remove the Identity column from the create statement I can achieve the result I am looking for, but I can't do this because I am using real tables. How can I make the query 'bypass' the id column and achieve my desired result
Since the PK is unique (an identity) for each row, you'll need to exclude it from the query or it will be including in the grouping aspect of PIVOT. To get around this, you'll want to use a subquery to select only the columns needed for the PIVOT.
Change your query to the follow:
Select item_name, Growth,Leverage
from
(
select item_name, item_value, decode
from #Test
where item_name = 'Threshold'
) d
Pivot
(
max(d.decode)
for d.item_value in (Growth,Leverage)
) as pvt;
See Demo.
Another option is to use a crosstab for this instead of PIVOT.
select item_name
,MAX(case when item_value = 'Growth' then decode end) as Growth
, MAX(case when item_value = 'Leverage' then decode end) as Leverage
from #Test
where item_name = 'Threshold'
group by item_name
;WITH CTE AS
(Select d.*,
ROW_NUMBER()OVER(PARTITION BY
item_name ORDER BY item_name DESC )rn
from #Test d)
Select item_name,
Growth,
Leverage
FROM
(select item_name, item_value, decode
from CTE
where item_name = 'Threshold' )d
Pivot (
max(d.decode)
for d.item_value in (Growth,Leverage)
) as pvt

How to create a sum column without an internal subquery?

I'm using SQL Server 2008 R2
I have a complex query which I need to have a conditionally summed column for it.
Here is a simplified version of my query and results:
DECLARE #t TABLE (id int, condition int, value int);
INSERT INTO #t
VALUES (1,1,12), (2,0,88), (3,1,11)
SELECT
*,
(SELECT SUM(value) FROM #t WHERE condition = 1) as SumOfConditionalValues
FROM #t
Here are the results of this query"
id condition value SumOfConditionalValues
1 1 12 23
2 0 88 23
3 1 11 23
I can't afford the SumOfConditionalValues sub query.
Is there an elegant way to achieve the conditionally summed column without it?
Which aggregate commands are suitable here, if any, and how do I apply these?
Try this:
SELECT *, SUM(CASE WHEN condition = 1 THEN value END) OVER() SumOfConditionalValues
FROM #t
See here: http://sqlfiddle.com/#!3/1abea/1
Use a self join:
CREATE TABLE MyTable (id int, condition int, value int);
INSERT INTO MyTable
VALUES (1,1,12), (2,0,88), (3,1,11)
SELECT
MyTable.id,
MyTable.Condition,
MyTable.value,
SUM(JoinedMyTable.Value)
FROM
MyTable
LEFT JOIN MyTable JoinedMyTable ON MyTable.condition = JoinedMyTable.Condition
GROUP BY
MyTable.id,
MyTable.Condition,
MyTable.value
EDIT: Don't know if you want every row to show the sum of rows where condition = 1, but if you do just change the join clause to be:
LEFT JOIN MyTable JoinedMyTable ON JoinedMyTable.Condition = 1
I believe what you are looking for is the "CASE' statement...Very powerful, for example:
select id, sum(case when condition=1 then value else 0 end) group by id..etc
Declare #sum int
SELECT #sum=SUM(value) FROM #t WHERE condition = 1
select *,#sum from yourtable
You can bring the results aggregated by condition:
DECLARE #t TABLE (id int, condition int, value int);
INSERT INTO #t VALUES (1,1,12), (2,0,88), (3,1,11)
SELECT *,
sum(value) over (partition by condition) as SumOfConditionalValues
FROM #t
I think this is what you want:
SELECT id, condition, value,
SUM(CASE WHEN condition = 1 THEN value_at_1 END) OVER() SumOfConditionalValues
FROM (select *,
(case when condition = 1 then value end) as value_at_1
from #t
) t
You need a "conditional value", which you can create in a subquery.