I have a column TASKID "3.001.2.2.1.3"
I have split them based on . (dot) in 4 columns with each column value:
TaskLevel1=3
TaskLevel2=3.001
TaskLevel3=3.001.2
TaskLevel4=3.001.2.2
The sample code for creating table and insert scripts are below:
CREATE TABLE [dbo].[Task]
(
[TaskID] [varchar](35) NULL,
[TaskLevel1] [varchar](35) NULL,
[TaskLevel2] [varchar](35) NULL,
[TaskLevel3] [varchar](35) NULL,
[TaskLevel4] [varchar](35) NULL
)
INSERT [dbo].[Task] ([TaskID], [TaskLevel1], [TaskLevel2], [TaskLevel3], [TaskLevel4])
VALUES (N'3.001.2.2.1', N'3', N'3.001', N'3.001.2', N'3.001.2.2')
INSERT [dbo].[Task] ([TaskID], [TaskLevel1], [TaskLevel2], [TaskLevel3], [TaskLevel4])
VALUES (N'3.001.2.2.1.3', N'3', N'3.001', N'3.001.2', N'3.001.2.2')
DECLARE #T TABLE (
[TaskID] [varchar](35) NULL
)
INSERT INTO #T VALUES
('3'),
('3.001'),
('3.001.2.2.1'),
('3.001.2.2.1.3')
;with cte([TaskID], [start], [level]) as
(
SELECT [TaskID], 1, 1
FROM #t
UNION ALL
SELECT [TaskID], CHARINDEX('.', [TaskID], [start]) + 1, [level] + 1
FROM cte
WHERE CHARINDEX('.', [TaskID], [start]) > 0
),
cte2 as
(
SELECT [TaskID], LEFT([TaskID], CHARINDEX('.', [TaskID] + '.', [start]) - 1) AS [val], [level]
FROM cte
)
SELECT [TaskID]
, [1] AS [TaskLevel1]
, [2] AS [TaskLevel2]
, [3] AS [TaskLevel3]
, [4] AS [TaskLevel4]
FROM cte2
PIVOT (MAX([val])
FOR [level] IN ([1], [2], [3], [4])) p
ORDER BY [TaskID]
Related
I have to create a Pivot from the below given sample table -
State Country
------------------------------
ALA Almaty Kazakhstan
AMD Ahmedabad India
AMM Amman Jordan
AMS Amsterdam Netherlands
ATH Athens Greece
AUH Abu Dhabi United Arab Emirates
BAH Manama Bahrain
I am doing this by dynamic sql as i want dynamic columns in pivot. My problem is that I am not able to sort values generated by ROW_NUMBER() in dynamic SQL. The variable #var1 in the below mentioned code is giving output as -
[1],[10],[11],[2],[3],[4],[5],[6],[7],[8],[9]
which is not in sorted order.
declare #myvar nvarchar(max)
declare #var1 nvarchar(max)
declare #new nvarchar(max)
set #var1 = (select stuff((select distinct '],[' + cast(ROW_NUMBER() over ( partition by country order by (select 1)) as varchar(100)) from sheet
for xml path('')),1,2,'') + ']')
select #var1
set #myvar =
'select * from
(select *,ROW_NUMBER() over (partition by country order by (select 1)) as rn
from sheet
)as abc
pivot
(
max([state]) for rn
in (' + #var1 + ')
) as pvt'
set #new = 'select * into ##a from (' + #myvar + ') as t'
exec sp_executesql #new
You can try this:
WITH cte
AS ( SELECT ROW_NUMBER() OVER ( PARTITION BY country ORDER BY ( SELECT 1 ) ) rn
FROM sheet
)
SELECT #var1 = STUFF(( SELECT '],[' + CAST(rn AS NVARCHAR(MAX))
FROM cte
GROUP BY rn
ORDER BY rn
FOR XML PATH('') ), 1, 2, '') + ']'
SELECT #var1
For test data it works:
DECLARE #t TABLE ( i INT )
DECLARE #var1 NVARCHAR(MAX)
INSERT INTO #t
VALUES ( 1 ),
( 1 ),
( 2 ),
( 2 ),
( 2 ),
( 3 ),
( 3 ),
( 3 ),
( 3 ),
( 3 ),
( 3 ),
( 3 ),
( 3 ),
( 3 ),
( 3 ),
( 3 ),
( 4 ),
( 4 );
WITH cte
AS ( SELECT ROW_NUMBER() OVER ( PARTITION BY i ORDER BY ( SELECT 1 ) ) rn
FROM #t
)
SELECT #var1 = STUFF(( SELECT '],[' + CAST(rn AS NVARCHAR(MAX))
FROM cte
GROUP BY rn
ORDER BY rn
FOR XML PATH('') ), 1, 2, '') + ']'
SELECT #var1
Output:
[1],[2],[3],[4],[5],[6],[7],[8],[9],[10],[11]
SQL Server 2008.
declare #pardate table ( pardateid int, pardatewhen datetime2(3) )
insert into #pardate values ( 1 , '2011-09-17 12:43' )
insert into #pardate values ( 2 , '2011-09-17 12:44' )
insert into #pardate values ( 3 , '2011-10-11 12:45' )
insert into #pardate values ( 4 , '2011-10-12 12:46' )
insert into #pardate values ( 5 , '2011-10-13 12:47' )
insert into #pardate values ( 6 , '2011-11-20 12:48' )
insert into #pardate values ( 7 , '2011-11-21 12:49' )
insert into #pardate values ( 8 , '2011-11-22 12:50' )
declare #child table ( childid int , pardateid int , childvalue char(6) )
insert into #child values ( 1 , 1 , 'aaaaaa' )
insert into #child values ( 2 , 2 , 'bbbbbb' )
insert into #child values ( 3 , 3 , 'cccccc' )
insert into #child values ( 4 , 4 , 'dddddd' )
insert into #child values ( 5 , 5 , 'cccccc' )
insert into #child values ( 6 , 6 , 'cccccc' )
insert into #child values ( 7 , 7 , 'eeeeee' )
insert into #child values ( 8 , 8 , 'ffffff' )
select pardatewhen , childvalue , COUNT(childvalue)
from #child childtable join #pardate parenttable on childtable.pardateid=parenttable.pardateid
group by pardatewhen , childvalue
I am trying to get a count of #child.childvalue every day, every hour, so there would be 8760 rows in my result.
First pass had a loop and a CONVERT which takes ~5 minutes to run with the actual result set (this is just a sample for illustation). I did create a CTE to make a calendar temp table (using http://www.sqlpointers.com/2006/07/generating-temporary-calendar-tables.html), and thought it could be joined somehow to add "empty values" into the result set.
I need to get a result set that looks like this
date hour count
...
2011-09-17 0 0
....
2011-09-17 12 2
....
2011-10-11 12 1
How can that be done efficiently?
Thanks.
try this.
;WITH cal AS
(SELECT CAST('2011-01-01' AS DATETIME) AS cal_date
UNION ALL
SELECT DATEADD(hour,1,cal_date)
FROM cal
WHERE cal_date < '2011-12-31 23:00'
)
, par AS
(
select CAST(pardatewhen AS DATE) AS pardate, DATEPART(hh,pardatewhen) AS parhour , COUNT(childvalue) as num
from #child childtable
join #pardate parenttable on childtable.pardateid=parenttable.pardateid
group by CAST(pardatewhen AS DATE), DATEPART(hh,pardatewhen)
)
SELECT CAST(cal.cal_date AS DATE) AS [date],DATEPART(hh,cal.cal_date) AS [hour],ISNULL(par.num,0) AS [childvalue_count]
FROM cal
LEFT JOIN par
ON CAST(cal.cal_date AS DATE) = par.pardate
AND DATEPART(hh,cal.cal_date) = par.parhour
OPTION (MAXRECURSION 9999)
Something like (have childvalue in your query but not in your example result?)
select Cast(pardatewhen as Date) as [date], DatePart(hour,pardatewhen) as [hour] , childvalue , COUNT(childvalue)
from #child childtable
join #pardate parenttable on childtable.pardateid=parenttable.pardateid
group by Cast(pardatewhen as Date), DatePart(hour,pardatewhen), childvalue
Note Date type was introduced in SQL 2008
I have a table with Comma Separated values in multiple Columns as
dept_rule |dept_descr|dept |dept_pos
-----------+----------+-------+--------
four rules |No descrrr|aaa,bbb|xxx,yyy
I want to seperate the values, as the below table
dept_rule |dept_descr|dept|dept_pos
----------+----------+----+--------
four rules|No descrrr|aaa |xxx
four rules|No descrrr|aaa |yyy
four rules|No descrrr|bbb |xxx
four rules|No descrrr|bbb |yyy
How to write query to do this.
Thanks in advance...
Here is the code for 2 values only in a column:
declare #a table (dept_rule varchar(10), dept_descr varchar(50), dept varchar(50), dept_pos varchar(50))
insert into #a values ('four rules','No descrrr', 'aaa,bbb', 'xxx,yyy')
select
dept_rule,
dept_descr,
dept_unp,
dept_post_unp
from
(
select
dept_rule,
dept_descr,
substring(dept, 0, charindex(',', dept)) as dept,
substring(dept, charindex(',', dept)+1, len(dept)) as dept1,
dept_post_unp
from
(
select
dept_rule,
dept_descr,
dept,
substring(dept_pos, 0, charindex(',', dept_pos)) as dept_pos,
substring(dept_pos, charindex(',', dept_pos)+1, len(dept_pos)) as dept_pos1
from #a
)to_unpivot1
unpivot
(
dept_post_unp for depts in(dept_pos, dept_pos1)
)unpivoted1
)to_unpivot2
unpivot
(
dept_unp for depts in(dept, dept1)
)unpivoted2
If dept and dept_pos have two values separated with comma, then this should help
CREATE TABLE #T1 (
dept_rule nvarchar(20),
dept_descr nvarchar(20),
dept nvarchar(20),
dept_pos nvarchar(20))
INSERT INTO #T1 VALUES (
'four rules',
'No descrrr',
'aaaa,bbbbb',
'xxx,yy'
)
;with T as (
select
dept_rule,
dept_descr,
dept,
dept_pos,
charindex(',', dept) pos1,
charindex(',', dept_pos) pos2
from #T1
)
select
dept_rule,
dept_descr,
LEFT(dept, pos1 - 1),
LEFT(dept_pos, pos2 - 1)
from T
UNION ALL
select
dept_rule,
dept_descr,
LEFT(dept, pos1 - 1),
RIGHT(dept_pos, LEN(dept_pos) - pos2)
from T
UNION ALL
select
dept_rule,
dept_descr,
RIGHT(dept, LEN(dept) - pos1),
LEFT(dept_pos, pos2 - 1)
from T
UNION ALL
select
dept_rule,
dept_descr,
RIGHT(dept, LEN(dept) - pos1),
RIGHT(dept_pos, LEN(dept_pos) - pos2)
from T
DROP TABLE #T1
UPDATE: More flexible solution - multiple separators. But each column with separators adds more complexity
-- separator
DECLARE #sep nvarchar(1) = ','
-- our data table
CREATE TABLE #T (
dept_rule nvarchar(20),
dept_descr nvarchar(20),
dept nvarchar(20),
dept_pos nvarchar(20)
)
-- sample data
INSERT INTO #T VALUES
('four rules', 'No descrrr', 'aaaaa,bbb,ccc', 'kk,ll,mm'),
('four rules', 'No descrrr', 'x,yyyy', 'sss,rrr'),
('four rules', 'No descrrr', 'zzz', 'xxxx,lll')
-- find occurences of separator in the column 'dept'
;WITH T AS (
SELECT
0 AS row,
0 AS start,
CHARINDEX(#sep, dept) pos,
dept
FROM #T
UNION ALL
SELECT
pos + 1,
pos,
CHARINDEX(#sep, dept, pos + 1),
dept
FROM T
WHERE
pos > 0
)
-- remember result of splitting first column
SELECT
#T.*,
a.part
INTO #Result1
FROM (
-- result with string parts
SELECT
T.dept,
T.start,
T.pos AS finish,
SUBSTRING(T.dept, T.start + 1, T.pos - (T.start + 1)) AS part
FROM T
WHERE
T.pos > 0
UNION ALL
-- but separators don't give us last part, append
SELECT
T.dept,
T.start,
T.pos AS finish,
RIGHT(T.dept, LEN(T.dept) - T.start) AS part
FROM T
WHERE
T.pos = 0
) a
INNER JOIN #T
ON #t.dept = a.dept
ORDER BY
a.dept,
a.start,
a.finish
-- SELECT * FROM #Result1
-- now second column
;WITH T2 AS (
SELECT
0 AS row,
0 AS start,
CHARINDEX(#sep, dept_pos) pos,
dept_pos
FROM #T
UNION ALL
SELECT
pos + 1,
pos,
CHARINDEX(#sep, dept_pos, pos + 1),
dept_pos
FROM T2
WHERE
pos > 0
)
-- append second column's splits to first result
SELECT
a.dept_rule,
a.dept_descr,
a.part AS part1,
b.part AS part2
FROM (
-- result with string parts
SELECT
T2.dept_pos,
T2.start,
T2.pos AS finish,
SUBSTRING(T2.dept_pos, T2.start + 1, T2.pos - (T2.start + 1)) AS part
FROM T2
WHERE
T2.pos > 0
UNION ALL
-- but separators don't give us last part, append
SELECT
T2.dept_pos,
T2.start,
T2.pos AS finish,
RIGHT(T2.dept_pos, LEN(T2.dept_pos) - T2.start) AS part
FROM T2
WHERE
T2.pos = 0
) b
INNER JOIN #Result1 a
ON a.dept_pos = b.dept_pos
-- clean up
DROP TABLE #T
DROP TABLE #Result1
UPDATE2: I based on first answer of Alex.K. to question SQL Server - find nth occurrence in a string - now it's improved and you may apply them to my solution
UPDATE3: Improved code based on link from UPDATE2
-- separator
DECLARE #sep nvarchar(1) = ','
-- our data table
CREATE TABLE #T (
dept_rule nvarchar(20),
dept_descr nvarchar(20),
dept nvarchar(20),
dept_pos nvarchar(20)
)
-- sample data
INSERT INTO #T VALUES
('four rules', 'No descrrr', 'aaaaa,bbb,ccc', 'kk,ll,mm'),
('four rules', 'No descrrr', 'x,yyyy', 'sss,rrr'),
('four rules', 'No descrrr', 'zzz', 'xxxx,lll')
-- find occurences of separator in the column 'dept'
;WITH T (dept, start, pos) AS (
SELECT
dept,
1,
CHARINDEX(#sep, dept)
FROM #T
UNION ALL
SELECT
dept,
pos + 1,
CHARINDEX(#sep, dept, pos + 1)
FROM T
WHERE
pos > 0
)
-- remember result of splitting first column
SELECT
#T.*,
a.token
INTO #Result1
FROM (
SELECT
*,
SUBSTRING(T.dept, T.start, CASE WHEN T.pos > 0 THEN T.pos - T.start ELSE LEN(T.dept) END) AS token
FROM T
) a
INNER JOIN #T
ON #t.dept = a.dept
ORDER BY
a.dept
-- now second column
;WITH T2 (dept_pos, start, pos) AS (
SELECT
dept_pos,
1,
CHARINDEX(#sep, dept_pos)
FROM #T
UNION ALL
SELECT
dept_pos,
pos + 1,
CHARINDEX(#sep, dept_pos, pos + 1)
FROM T2
WHERE
pos > 0
)
-- append second column's splits to first result
SELECT
a.dept_rule,
a.dept_descr,
a.token AS token1,
b.token AS token2
FROM (
SELECT
*,
SUBSTRING(T2.dept_pos, T2.start, CASE WHEN T2.pos > 0 THEN T2.pos - T2.start ELSE LEN(T2.dept_pos) END) AS token
FROM T2
) b
INNER JOIN #Result1 a
ON a.dept_pos = b.dept_pos
-- clean up
DROP TABLE #T
DROP TABLE #Result1
Edit - restating my need since two guys with way more rank than me misunderstood my question, so I need to make this better...
I have a table like the below. I need to select all of the rows for the first group of 'sec1' rows where the 'ison' column is 1. So the query should first return the 'bbb' row, but if I set all rows to ison=0 and then make the 'ccc' rows ison=1, then I would get two rows of 'ccc' in the result set. Can anyone help me with my rank/top? Using MSSQL 2008.
create table #grp ( sec1 varchar(4) , sec2 varchar(4) , ison bit )
insert into #grp values ( 'aaa' , '001' , 0 )
insert into #grp values ( 'aaa' , '002' , 0 )
insert into #grp values ( 'bbb' , '001' , 1 )
insert into #grp values ( 'ccc' , '001' , 1 )
insert into #grp values ( 'ccc' , '001' , 1 )
Select * From
( Select
sec1 ,
sec2 ,
ison ,
RANK() Over ( partition by sec1 order by sec1,sec2 ) as rowrank
from #grp
where ison=1
) tmp
where rowrank=1
Thanks.
create table #grp ( sec1 varchar(4) , sec2 varchar(4) , ison bit )
insert into #grp values ( 'aaa' , '001' , 0 )
insert into #grp values ( 'aaa' , '002' , 1 )
insert into #grp values ( 'bbb' , '001' , 1 )
insert into #grp values ( 'ccc' , '001' , 1 )
insert into #grp values ( 'ccc' , '001' , 1 )
SELECT *
FROM #grp
WHERE sec1 = (
Select TOP(1) sec1
From
( Select
sec1 ,
sec2 ,
ison ,
RANK() Over ( partition by sec1 order by sec1,sec2 ) as rowrank
from #grp
where ison=1
) tmp
where rowrank=1
Order by sec1, Sec2
)
SQL Server 2008, I have the following parent/child table schemata and rows:
create table #par( parid int primary key identity(1,1) , partext varchar(6) )
create table #chi( chiid int primary key identity(1,1) , parid int null , chirefid int null , chiinfo varchar(6) )
create table #chiref ( chirefid int primary key identity(1,1) , chisubdesc varchar(9) )
insert into #par values ( 'par1' ) , ('par2')
insert into #chiref values ( 'chi1' )
insert into #chiref values ( 'chi2' )
insert into #chiref values ( 'chi3' )
insert into #chi values ( 1 , 1 , 'aaa' )
insert into #chi values ( 1 , 2 , 'bbb' )
insert into #chi values ( 2 , 1 , 'ccc' )
insert into #chi values ( 2 , 2 , 'ddd' )
insert into #chi values ( 2 , 3 , 'eee' )
The child #chi has just key/value pairs inside, and I need to convert the text (key) into a column and put the value inside, so the result set is shaped like the below. What is the best way to do that (I cannot change the key/value stuff, it is inherited from another system). And there is a join on the #chiref table for the actual column names (which is really killing me).
partext chi1 chi2 chi3
par1 aaa bbb
par2 ccc ddd eee
Thanks.
EDIT - The thing to remember is that the column names have to match the "key value" in the table. So if the EAV row key is "chi1" then the pivot has to have "chi1". I had simply "1" which broke. So I got it.
Thanks again!
select partext, [chi1], [chi2], [chi3]
from
(
select p.partext, c.chitext, c.chiinfo
from #chi c
join #par p
on c.parid = p.parid
) AS SourceTable
pivot
(
min(chiinfo)
for chitext in ([chi1], [chi2], [chi3])
) as PivotTable
or this one is a little more efficient, although more code:
with c
as
(
select parid, [chi1], [chi2], [chi3]
from
(
select parid, chitext, chiinfo
from #chi
) AS SourceTable
pivot
(
min(chiinfo)
for chitext in ([chi1], [chi2], [chi3])
) as PivotTable
)
select p.partext, c.*
from c
join #par p
on c.parid = p.parid
if you need a dynamic column number, you can do dynamic query:
declare #ColumnList varchar(max)
select #ColumnList = isnull(#columnList + ', ', '') + '[' + chitext + ']'
from
(
select distinct chitext
from #chi
) tt
order by chitext
declare #Command varchar(max) = '
with c
as
(
select parid, ' + #ColumnList + '
from
(
select parid, chitext, chiinfo
from #chi
) AS SourceTable
pivot
(
min(chiinfo)
for chitext in (' + #ColumnList + ')
) as PivotTable
)
select p.partext, ' + #ColumnList + '
from c
join #par p
on c.parid = p.parid
'
execute(#Command)