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)
Related
I am new to this and i am wondering how to input data into SSRS table and auto generate for the subsequent months. This is the format of the table.
Appreciated for any help given.
You can generate a date range using the following SQL
DECLARE #date_start AS DATETIME
SET #date_start = '01-DEC-2017'
;WITH
finalvalues
AS
(
SELECT tbl.* FROM (VALUES
( '01-Dec-2017', 6414.6563, 429.6846, -1390.8474)
, ( '02-Dec-2017', 6476.6563, 432.751, -1312.4928)
, ( '03-Dec-2017', 6538.6563, 435.8174, -1234.1382)
, ( '04-Dec-2017', 6600.6563, 438.8838, -1155.7836)
, ( '05-Dec-2017', 6662.6563, 441.9502, -1077.429)
, ( '06-Dec-2017', 6724.6563, 445.0166, -999.074399999999)
, ( '07-Dec-2017', 6786.6563, 448.083, -920.719799999999)
, ( '08-Dec-2017', 6848.6563, 451.1494, -842.365199999999)
, ( '09-Dec-2017', 6910.6563, 454.2158, -764.010599999999)
, ( '10-Dec-2017', 6972.6563, 457.2822, -685.655999999999)
, ( '11-Dec-2017', 7034.6563, 460.3486, -607.301399999999)
, ( '12-Dec-2017', 7096.6563, 463.415, -528.946799999999)
, ( '13-Dec-2017', 7158.6563, 466.4814, -450.592199999999)
, ( '14-Dec-2017', 7220.6563, 469.5478, -372.2376)
, ( '15-Dec-2017', 7282.6563, 472.6142, -293.883)
, ( '16-Dec-2017', 7344.6563, 475.6806, -215.5284)
) tbl ([Date], [IncLoad], [ITLoad], [RH])
)
,
manufactured_dates
AS
(
SELECT
day_date = DATEADD(day, dte.[number], #date_start)
FROM
master.dbo.spt_values AS dte
WHERE
1=1 -- <-- used in testing to be able to comment out other clauses below
AND dte.[type] = 'P'
AND dte.[number] <= 365 -- <-- filter how many rows you want to see here
)
SELECT
'Date' = md.[day_date]
, 'IncLoad' = AVG(incload)
, 'ITLoad' = AVG(ITLoad)
FROM
finalvalues AS fv
FULL OUTER JOIN manufactured_dates AS md ON md.[day_date] = fv.[Date]
GROUP BY
md.[day_date]
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]
The webguys wants unique urls based on the name of the products
If more products have the same name, add a number after the name.
our.dom/red-sock
our.dom/red-sock-1
They do not want the product id or another number on all products, i.e.
our.dom/red-sock-123481354
I store this in a field i call seourl.
I have it covered when I create new products, a trigger tries adding the seourl, if it is already there, increment the number, until an unique value is found.
But I now have to give the entire table new seourls.
If I just
update tab set seourl=dbo.createurl(title)
I am sure to have collissions, and the operation is rolled back.
Is there a way to have the statement to commit the updates that work, and leave the rest unchanged?
Or must I just do a RBAR, Row By Agonizing Row operation in a loop?
Adapt this to your needs:
select
*
from (values('aaa'), ('aaa-12'), ('aaa-'), ('bbb-3')) as src (x)
cross apply (
select isnull(nullif(patindex('%-[0-9]%', x) - 1, -1), LEN(x))
) as p(idx)
cross apply (
select
SUBSTRING(x, 1, idx)
, SUBSTRING(x, idx + 1, LEN(x) - idx)
) as t(t, xx)
Try this:
declare #tmp table (
id int not null identity
, name varchar(100) -- you need name to be indexed
, urlSuffix int -- store the number (ot you'll have to use PATINDEX, etc. as previously shown)!
, url as name + ISNULL('_' + cast(NULLIF(urlSuffix, 0) as varchar(100)), '')
, unique (name, id) -- (trick) index on name
)
insert #tmp (name, urlSuffix)
select
src.name
, ISNULL(T.urlSuffix, -1) + ROW_NUMBER() OVER (PARTITION BY src.name ORDER BY (select 1))
from (values
('x')
, ('y')
, ('y')
, ('y')
, ('z')
, ('z')
) as src (name)
left join (
select
name
, MAX(T.urlSuffix) as urlSuffix
from #tmp AS T
GROUP BY name
) as T on (
T.name = src.name
)
insert #tmp (name, urlSuffix)
select
src.name
, ISNULL(T.urlSuffix, -1) + ROW_NUMBER() OVER (PARTITION BY src.name ORDER BY (select 1))
from (values
('a')
, ('b')
, ('b')
, ('b')
, ('z')
, ('z')
) as src (name)
left join (
select
name
, MAX(T.urlSuffix) as urlSuffix
from #tmp AS T
GROUP BY name
) as T on (
T.name = src.name
)
select
name, url
from #tmp
order by url
The solution to yur problem should lies in the use of ROW_NUMBER()
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 need a sql query for my table tbl1
sample contents of the table like this
serial ida idb
1 1 2
2 1 3
3 3 7
4 3 6
5 2 4
6 2 6
.
in the table tbl1 column ida and idb are related like 1 is related with 2 and 3 , 2 is related with 4 and 6
ida value 1 s related data is 2 and 3 and i want to select the related data of 1' s related data (2 and 3).
2 and 3 s related data is 7, 6 and 4, 6. so the output will be (7,6,4)
. i need a sql query to display this out put. can anyone share some idea how to do that ..
SELECT DISTINCT idb FROM tbl1 WHERE ida = 2 OR ida = 3;
Is this what you were looking for?
EDIT: Corrected determining child branches of the hierarchy.
This may be of some use:
-- Sample data.
declare #Table as table ( serial int identity, ida int, idb int )
insert into #Table ( ida, idb ) values
( 1, 2 ), ( 1, 3 ),
( 3, 7 ), ( 3, 6 ),
( 2, 4 ), ( 2, 6 )
select * from #Table
-- Demonstrate recursive query.
; with CTE as (
-- Start with ida = 1.
select serial, ida, idb, 1 as depth, path = cast( right( '000000' + cast( ida as varchar(6) ), 6 ) as varchar(1024) )
from #Table
where ida = 1
union all
-- Add each row related to the most recent selected row(s).
select T.serial, T.ida, T.idb, C.depth + 1, cast( C.path + right( '000000' + cast( T.ida as varchar(6) ), 6 ) as varchar(1024) )
from CTE as C inner join
#Table as T on T.ida = C.idb
)
-- Show everything.
select *
from CTE
-- Repeat the recursive query.
; with CTE as (
-- Start with ida = 1.
select serial, ida, idb, 1 as depth, path = cast( right( '000000' + cast( ida as varchar(6) ), 6 ) as varchar(1024) )
from #Table
where ida = 1
union all
-- Add each row related to the most recent selected row(s).
select T.serial, T.ida, T.idb, C.depth + 1, cast( C.path + right( '000000' + cast( T.ida as varchar(6) ), 6 ) as varchar(1024) )
from CTE as C inner join
#Table as T on T.ida = C.idb
)
-- Select only the deepest children.
select distinct idb
from CTE as C
where not exists ( select 42 from CTE where left( path, len( C.path ) ) = C.path and len( path ) > len( C.path ))
order by idb
Left as an exercise is pivoting the result.
select distinct idb from tbl1 where ida in (select idb from tbl1 where ida = 1)