Related
I'm trying to create a report in Tableau to generate a tree structure of all the work items in TFS 2015 and their respective hierarchy
Such as
Epic->Features->User Story->Task
But repeated attempts to create the sql query have failed. Could you please help me with the SQL query that could help fetch all the work items and display their hierarchy?
Thanks.
Instead of using SQL Query, it's suggested to use TFS REST API to create a query in TFS, the WIQL looks like:
"wiql": "select [System.Id], [System.WorkItemType], [System.Title], [System.AssignedTo], [System.State], [System.Tags] from WorkItemLinks where (Source.[System.TeamProject] = 'xxx' and Source.[System.WorkItemType] <> '' and Source.[System.State] <> '') and ([System.Links.LinkType] = 'System.LinkTypes.Hierarchy-Forward') and (Target.[System.WorkItemType] <> '') order by [System.Id] mode (Recursive)"
So, i have found this query, which is working and can help you create a tableau workbook for the hierarchy:
WITH cte
AS ( SELECT DimTeamProject.ProjectNodeName ,
System_WorkItemType ,
DimWorkItem.System_Id ,
FactWorkItemLinkHistory.TargetWorkItemID ,
DimWorkItem.System_Title,
DimWorkItem.System_State,
DimWorkItem.Microsoft_VSTS_Common_ActivatedDate,
DimWorkItem.Microsoft_VSTS_Scheduling_TargetDate,
DimWorkItem.System_CreatedDate,
DimWorkItemLinkType.LinkName,
TeamProjectSK,
system_rev,
row_number() over( partition by system_id,TeamProjectSK, FactWorkItemLinkHistory.TargetWorkItemID order by system_rev desc ) rownum
FROM DimWorkItem ,
DimTeamProject ,
FactWorkItemLinkHistory,
DimWorkItemLinkType
WHERE DimWorkItem.TeamProjectSK = DimTeamProject.ProjectNodeSK
AND DimWorkItem.System_Id = FactWorkItemLinkHistory.SourceWorkItemID
and DimWorkItemLinkType.WorkItemLinkTypeSK = FactWorkItemLinkHistory.WorkItemLinkTypeSK
/* -To Test the Query using the project Name of our choice- */
--AND ProjectNodeName =
AND System_State in ('ACTIVE','NEW')
/* -System Revisions are created when the entry is modified. Onlt the latest entry will have the below revised date- */
AND System_RevisedDate = '9999-01-01 00:00:00.000'
AND DimWorkItemLinkType.Linkname IN ( 'Parent',
'child' )
GROUP BY DimTeamProject.ProjectNodeName ,
DimWorkItem.System_Id ,
FactWorkItemLinkHistory.TargetWorkItemID ,
DimWorkItem.System_Title ,
System_WorkItemType,
DimWorkItem.System_State,
TeamProjectSK,
DimWorkItemLinkType.LINKName,
DimWorkItem.Microsoft_VSTS_Common_ActivatedDate,
DimWorkItem.Microsoft_VSTS_Scheduling_TargetDate,
DimWorkItem.System_CreatedDate,
system_rev
)
SELECT distinct t1.ProjectNodeName ,
t1.System_Id requirement_Id ,
t1.System_WorkItemType,
t1.System_Title requirement_title ,
t2.System_Id Change_request_id ,
t1.LinkName,
t2.System_Title Change_Request_Title,
t1.Microsoft_VSTS_Common_ActivatedDate,
t1.System_CreatedDate,
t1.Microsoft_VSTS_Scheduling_TargetDate,
t1.System_State,
T1.rownum
FROM cte t1
INNER JOIN cte t2 ON t1.TargetWorkItemID = t2.System_Id
and t1.rownum = 1
ORDER BY t1.System_Id;
Used a CTE to find get the complete hierarchy, its faster and more efficient than the query posted before.
I have data in a table which looks like:
I want to split its data and make it look like the following through a sql query in Oracle (without using pivot):
How can it be done?? is there any other way of doing so without using pivot?
You need to use a pivot query here to get the output you want:
SELECT Name,
MIN(CASE WHEN ID_Type = 'PAN' THEN ID_No ELSE NULL END) AS PAN,
MIN(CASE WHEN ID_Type = 'DL' THEN ID_No ELSE NULL END) AS DL,
MIN(CASE WHEN ID_Type = 'Passport' THEN ID_No ELSE NULL END) AS Passport
FROM yourTable
GROUP BY Name
You could also try using Oracle's built in PIVOT() function if you are running version 11g or later.
Since you mention without using PIVOT function, you can try to
use SQL within group for moving rows onto one line and listagg to display multiple column values in a single column.
In Oracle 11g, we can use the listagg built-in function :
select
deptno,
listagg (ename, ',')
WITHIN GROUP
(ORDER BY ename) enames
FROM
emp
GROUP BY
deptno
Which should give you the below result:
DEPTNO ENAMES
------ --------------------------------------------------
10 CLARK,KING,MILLER
20 ADAMS,FORD,JONES,SCOTT,SMITH
30 ALLEN,BLAKE,JAMES,MARTIN,TURNER,WARD
You can find all the solution(s) to this problem here:
http://www.dba-oracle.com/t_converting_rows_columns.htm
For Oracle 11g and above, you could use PIVOT.
For pre-11g release, you could use MAX and CASE.
A common misconception, about PIVOT better in terms of performance than the old way of MAX and DECODE. But, under the hood PIVOT is same MAX + CASE. You can check it in 12c where Oracle added EXPAND_SQL_TEXT procedure to DBMS_UTILITY package.
For example,
SQL> variable c clob
SQL> begin
2 dbms_utility.expand_sql_text(Q'[with choice_tbl as (
3 select 'Jones' person,1 choice_nbr,'Yellow' color from dual union all
4 select 'Jones',2,'Green' from dual union all
5 select 'Jones',3,'Blue' from dual union all
6 select 'Smith',1,'Orange' from dual
7 )
8 select *
9 from choice_tbl
10 pivot(
11 max(color)
12 for choice_nbr in (1 choice_nbr1,2 choice_nbr2,3 choice_nbr3)
13 )]',:c);
14 end;
15 /
PL/SQL procedure successfully completed.
Now let's see what Oracle actually does internally:
SQL> set long 100000
SQL> print c
C
--------------------------------------------------------------------------------
SELECT "A1"."PERSON" "PERSON",
"A1"."CHOICE_NBR1" "CHOICE_NBR1",
"A1"."CHOICE_NBR2" "CHOICE_NBR2",
"A1"."CHOICE_NBR3" "CHOICE_NBR3"
FROM (
SELECT "A2"."PERSON" "PERSON",
MAX(CASE WHEN ("A2"."CHOICE_NBR"=1) THEN "A2"."COLOR" END ) "CHOICE_NBR1",
MAX(CASE WHEN ("A2"."CHOICE_NBR"=2) THEN "A2"."COLOR" END ) "CHOICE_NBR2",
MAX(CASE WHEN ("A2"."CHOICE_NBR"=3) THEN "A2"."COLOR" END ) "CHOICE_NBR3"
FROM (
(SELECT 'Jones' "PERSON",1 "CHOICE_NBR",'Yellow' "COLOR" FROM "SYS"."DUAL" "A7") UNION ALL
(SELECT 'Jones' "'JONES'",2 "2",'Green' "'GREEN'" FROM "SYS"."DUAL" "A6") UNION ALL
(SELECT 'Jones' "'JONES'",3 "3",'Blue' "'BLUE'" FROM "SYS"."DUAL" "A5") UNION ALL
(SELECT 'Smith' "'SMITH'",1 "1",'Orange' "'ORANGE'" FROM "SYS"."DUAL" "A4")
) "A2"
GROUP BY "A2"."PERSON"
) "A1"
SQL>
Oracle internally interprets the PIVOT as MAX + CASE.
You're able to create a non-pivot query by understanding what the pivot query will do:
select *
from yourTable
pivot
(
max (id_no)
for (id_type) in ('PAN' as pan, 'DL' as dl, 'Passport' as passport)
)
What the pivot does is GROUP BY all columns not specified inside the PIVOT clause (actually, just the name column), selecting new columns in a subquery fashion based on the aggregations before the FOR clause for each value specified inside the IN clause and discarding those columns specified inside the PIVOT clause.
When I say "subquery fashion" I'm refering to one way to achieve the result got with PIVOT. Actually, I don't know how this works behind the scenes. This subquery fashion would be like this:
select <aggregation>
from <yourTable>
where 1=1
and <FORclauseColumns> = <INclauseValue>
and <subqueryTableColumns> = <PIVOTgroupedColumns>
Now you identified how you can create a query without the PIVOT clause:
select
name,
(select max(id_no) from yourTable where name = t.name and id_type = 'PAN') as pan,
(select max(id_no) from yourTable where name = t.name and id_type = 'DL') as dl,
(select max(id_no) from yourTable where name = t.name and id_type = 'Passport') as passport
from yourTable t
group by name
You can use CTE's to break the data down and then join them back together to get what you want:
WITH NAMES AS (SELECT DISTINCT NAME
FROM YOURTABLE),
PAN AS (SELECT NAME, ID_NO AS PAN
FROM YOURTABLE
WHERE ID_TYPE = 'PAN'),
DL AS (SELECT NAME, ID_NO AS DL
FROM YOURTABLE
WHERE ID_TYPE = 'DL'),
PASSPORT AS (SELECT NAME, ID_NO AS "Passport"
FROM YOURTABLE
WHERE ID_TYPE = 'Passport')
SELECT n.NAME, p.PAN, d.DL, t."Passport"
FROM NAMES n
LEFT OUTER JOIN PAN p
ON p.NAME = n.NAME
LEFT OUTER JOIN DL d
ON d.NAME = p.NAME
LEFT OUTER JOIN PASSPORT t
ON t.NAME = p.NAME'
Replace YOURTABLE with the actual name of your table of interest.
Best of luck.
I have 2 two tables questionpool and question where question is a many to one of question pool. I have created a query using a sub select query which returns the correct random results but I need to return more than one column from the question table.
The intent of the query is to return a random test from the 'question' table for each 'QuizID' from the 'Question Pool' table.
SELECT QuestionPool.QuestionPoolID,
(
SELECT TOP (1) Question.QuestionPoolID
FROM Question
WHERE Question.GroupID = QuestionPool.QuestionPoolID
ORDER BY NEWID()
)
FROM QuestionPool
WHERE QuestionPool.QuizID = '5'
OUTER APPLY is suited to this:
Select *
FROM QuestionPool
OUTER APPLY
(
SELECT TOP 1 *
FROM Question
WHERE Question.GroupID = QuestionPool.QuestionPoolID
ORDER BY NEWID()
) x
WHERE QuestionPool.QuizID = '5'
Another example of OUTER APPLY use http://www.ienablemuch.com/2012/04/outer-apply-walkthrough.html
Live test: http://www.sqlfiddle.com/#!3/d8afc/1
create table m(i int, o varchar(10));
insert into m values
(1,'alpha'),(2,'beta'),(3,'delta');
create table x(i int, j varchar, k varchar(10));
insert into x values
(1,'a','hello'),
(1,'b','howdy'),
(2,'x','great'),
(2,'y','super'),
(3,'i','uber'),
(3,'j','neat'),
(3,'a','nice');
select m.*, '' as sep, r.*
from m
outer apply
(
select top 1 *
from x
where i = m.i
order by newid()
) r
Not familiar with SQL server, but I hope this would do:
Select QuestionPool.QuestionPoolID, v.QuestionPoolID, v.xxx -- etc
FROM QuestionPool
JOIN
(
SELECT TOP (1) *
FROM Question
WHERE Question.GroupID = QuestionPool.QuestionPoolID
ORDER BY NEWID()
) AS v ON v.QuestionPoolID = QuestionPool.QuestionPoolID
WHERE QuestionPool.QuizID = '5'
Your query appears to be bringing back an arbitrary Question.QuestionPoolId for each QuestionPool.QuestionPoolId subject to the QuizId filter.
I think the following query does this:
select qp.QuestionPoolId, max(q.QuestionPoolId) as any_QuestionPoolId
from Question q join
qp.QuestionPoolId qp
on q.GroupId = qp.QuestionPoolId
WHERE QuestionPool.QuizID = '5'
group by qp.QuestionPoolId
This returns a particular question.
The following query would allow you to get more fields:
select qp.QuestionPoolId, q.*
from (select q.*, row_number() over (partition by GroupId order by (select NULL)) as randrownum
from Question q
) join
(select qp.QuestionPoolId, max(QuetionPool qp
on q.GroupId = qp.QuestionPoolId
WHERE QuestionPool.QuizID = '5' and
randrownum = 1
This uses the row_number() to arbitrarily enumerate the rows. The "Select NULL" provides the random ordering (alternatively, you could use "order by GroupId".
Common Table Expressions (CTEs) are rather handy for this type of thing...
http://msdn.microsoft.com/en-us/library/ms175972(v=sql.90).aspx
I am trying to creat a View in SQL server 2000 using the Enterprise Manager that some times doesn't return any rows and when it doesn't i need it to return a 0.
I have tried this but I keep getting this message when I try to save it:
The Query Designer does not support
the IF SQL construct.
IF EXISTS (SELECT dbo.oehdrhst_sql.cus_no, dbo.oehdrhst_sql.inv_dt, dbo.oehdrhst_sql.inv_no, dbo.OELINHST_SQL.item_no,
dbo.OELINHST_SQL.item_desc_1, dbo.OELINHST_SQL.item_desc_2, dbo.OELINHST_SQL.qty_to_ship, dbo.IMITMIDX_SQL.user_def_fld_1,
dbo.IMITMIDX_SQL.user_def_fld_2, dbo.IMITMIDX_SQL.user_def_fld_3, dbo.IMITMIDX_SQL.user_def_fld_4,
dbo.IMITMIDX_SQL.user_def_fld_5, dbo.oehdrhst_sql.ord_type, dbo.oehdrhst_sql.orig_ord_type, dbo.OELINHST_SQL.qty_return_to_stk,
dbo.OELINHST_SQL.qty_to_ship * dbo.IMITMIDX_SQL.user_def_fld_2 AS extended, CONVERT(datetime, STR(dbo.oehdrhst_sql.inv_dt, 8, 0))
AS [Date]
FROM dbo.oehdrhst_sql INNER JOIN
dbo.OELINHST_SQL ON dbo.oehdrhst_sql.ord_no = dbo.OELINHST_SQL.ord_no INNER JOIN
dbo.IMITMIDX_SQL ON dbo.OELINHST_SQL.item_no = dbo.IMITMIDX_SQL.item_no
WHERE (dbo.oehdrhst_sql.inv_dt BETWEEN 20100701 AND 20110630) AND (dbo.OELINHST_SQL.item_no BETWEEN '3065 0' AND
'3065 ZZZZZZZZZZ') AND (NOT (dbo.IMITMIDX_SQL.user_def_fld_2 IS NULL)))
SELECT EXTENDED, cus_no, inv_dt, inv_no, item_no, item_desc_1, item_desc_2, qty_to_ship, user_def_fld_1, user_def_fld_2, [date]
FROM (SELECT dbo.oehdrhst_sql.cus_no, dbo.oehdrhst_sql.inv_dt, dbo.oehdrhst_sql.inv_no, dbo.OELINHST_SQL.item_no,
dbo.OELINHST_SQL.item_desc_1, dbo.OELINHST_SQL.item_desc_2, dbo.OELINHST_SQL.qty_to_ship,
dbo.IMITMIDX_SQL.user_def_fld_1, dbo.IMITMIDX_SQL.user_def_fld_2, dbo.IMITMIDX_SQL.user_def_fld_3,
dbo.IMITMIDX_SQL.user_def_fld_4, dbo.IMITMIDX_SQL.user_def_fld_5, dbo.oehdrhst_sql.ord_type, dbo.oehdrhst_sql.orig_ord_type,
dbo.OELINHST_SQL.qty_return_to_stk, dbo.OELINHST_SQL.qty_to_ship * dbo.IMITMIDX_SQL.user_def_fld_2 AS extended,
CONVERT(datetime, STR(dbo.oehdrhst_sql.inv_dt, 8, 0)) AS [Date]
FROM dbo.oehdrhst_sql INNER JOIN
dbo.OELINHST_SQL ON dbo.oehdrhst_sql.ord_no = dbo.OELINHST_SQL.ord_no INNER JOIN
dbo.IMITMIDX_SQL ON dbo.OELINHST_SQL.item_no = dbo.IMITMIDX_SQL.item_no
WHERE (dbo.oehdrhst_sql.inv_dt BETWEEN 20100701 AND 20110630) AND (dbo.OELINHST_SQL.item_no BETWEEN '3065 0' AND
'3065 ZZZZZZZZZZ') AND (NOT (dbo.IMITMIDX_SQL.user_def_fld_2 IS NULL))) a
GROUP BY EXTENDED, cus_no, inv_dt, inv_no, item_no, item_desc_1, item_desc_2, qty_to_ship, user_def_fld_1, user_def_fld_2, [date] ELSE
SELECT EXTENDED = 0
You can probably drop the IF EXISTS portion and just use an ISNULL(EXTENDED,0). That assumes a lot though.
This is not something you should do in the view. Instead do it when you CALL the view, i.e.:
IF (SELECT COUNT(*) FROM v_MyView) > 0
BEGIN
SELECT * FROM v_MyView
END
ELSE
SELECT 0
I have a table called TaskLog that holds the results of various scheduled tasks. It has (for the purposes of this question) these columns:
TaskLogID: unique ID for this record
TaskID: ID of the task that ran
HostName: name of the host on which it ran
RunDate: date and time on which the task was run
Output: output of this run
In order to get the output from the latest run of each task, I had been executing multiple queries, until I worked out this single query which is much faster:
SELECT TaskLog.TaskID, TaskLog.HostName, TaskLog.Output
FROM TaskLog
INNER JOIN (
SELECT TaskLogID, TaskID, HostName, MAX(RunDate)
FROM TaskLog
GROUP BY TaskID, HostName
) AS Latest
USING (TaskLogID)
Now I'd like to get the output from each of the last N runs of each task, for some fixed N, instead of just the latest run. Is there a way to do this in a single query?
TIA
Untested as I don't have MySQL installed on this machine (based on here)
select TaskLogID,
TaskID,
HostName,
RunDate
from (select TaskLogID,
TaskID,
HostName,
RunDate,
#num := if(#group = concat(TaskID, HostName), #num + 1, 1) as row_number,
#group := concat(TaskID, HostName) as dummy
from TaskLog) as x
where row_number <= 5;
This is where MySQL lack of window functions such as Row_Number() really hurts.
Select T.TaskLogId, T.TaskId, T.HostName, T.RunDate
From TaskLog As T
Join (
Select T1.TaskLogId
, (Select Count(*)
From TaskLog as T2
Where T2.TaskId = T1.TaskId
And T2.RunDate < T1.RunDate) + 1 As Rnk
From TaskLog As T1
) As RankedTasks
On RankedTasks.TaskLogId = T.TaskLogId
And RankedTasks.Rnk <= <somevalue>
Order By T.TaskId, T.RunDate
ADDITION
Assuming that TaskLogId is an auto increment column, you might be able to something like the following (In this example, I assumed you requested the top 5 items):
Select T.TaskLogId, T.TaskId, T.HostName, T.RunDate
From TaskLog As T
Join (
Select Tasks1.TaskId
, (
Select T4.TaskLogId
From TaskLog As T4
Where T4.TaskId = Tasks.TaskId
Order By T4.RunDate Desc
Limit 5, 1
) As UpperTaskLogId
From (
Select T3.TaskId
From TaskLog As T3
Group By T3.TaskId
) As Tasks1
) As LastId
On LastId.TaskId = T.TaskId
And LastId.UpperTaskLogId >= T.TaskLogId