Query TFS database to fetch last 10 check-in details - sql

Is there a way to query TFS database to get the last 10 check-in details
The output should be something like
File name | Comment | Changed By | Date
----------------------------------------------------------------------------
Test.cs Added new functionality username 01/08/2010
I am aware that the above result set can be obtained using TFS SDK. But I want to know if
there is a way to query the TFS database to fetch the above data.
Thanks

If I understand your question correctly, this will get you most of the way there in SQL:
SELECT TOP 10
V.ChildItem AS [File name],
CS.Comment,
I.DisplayName AS [Changed By],
CS.CreationDate AS [Date]
FROM tbl_Changeset CS
INNER JOIN tbl_Identity I ON I.IdentityID = CS.OwnerID
INNER JOIN tbl_Version V ON V.VersionFrom = CS.ChangesetID
ORDER BY CS.CreationDate DESC
There are some escaped characters in the file names that showed up while I was testing this on my TFS instance (like underscore characters become ">"). Other than that this should serve you well.

A lot of these queries are no longer relevant with newer instances of TFS. One of the big reasons is that the user identities (tbl_Identity) have been moved. Tfs_DefaultCollection is the DB that stored all information pertinent to a given Collection, but TFS can host multiple Collections AND an Admin can change the name of the default Collection when they are setting up TFS.
As such, all user identities have been moved to the Tfs_Configuration database;
select * from [tfs_Configuration].dbo.tbl_Identity
Gaining Access to the descriptive part of the account name ( AccountName or DisplayName ) from a Collection DB is accomplished by Join from [tfs_DefaultCollection].dbo.tbl_IdentityMap
select *
from [tfs_Configuration].dbo.tbl_Identity I
JOIN [tfs_DefaultCollection].dbo.tbl_IdentityMap IM
ON I.Id = IM.MasterID
With this information in hand, we can now produce the following query to show the last 100 ChangeSets committed to TFS as well as the name of the committer.
select top 100 *
from tbl_changeset as c
JOIN tbl_IdentityMap IM
ON C.OwnerID = IM.localId
JOIN tfs_configuration.dbo.tbl_Identity u
ON IM.MasterID = u.Id
Order by C.ChangeSetID DESC
Looking at this data, we can see A LOT of IDs, Sids, Lookups, etc. What we will NOT see in this data is any information about the File that was committed or information about the Branch the Commit was made to. This information comes from the tbl_Version table.
select top 100 *
from [tfs_DefaultCollection].dbo.tbl_changeset as c
JOIN [tfs_DefaultCollection].dbo.tbl_IdentityMap IM
ON C.OwnerID = IM.localId
JOIN [tfs_configuration].dbo.tbl_Identity u
ON IM.MasterID = u.Id
JOIN [tfs_DefaultCollection].dbo.tbl_Version as v
ON v.Versionfrom = c.ChangeSetId
Order by C.ChangeSetID DESC
[tfs_DefaultCollection].dbo.tbl_Version has a few columns of interest, namely; ParentPath, ChildItem & FullPath. What is missing here is any useful information regarding the Branch that the commit was made to. Branch info is embedded in either of the 2 available Path fields;
$\da3da7cf"80b5"4385"b3dc"ebb3088f3c01\Features\Inpatient\Source\Yadda\Yadda\Yadda\
This begs the next question, where is Branch info stored in TFS? Thanks to StackOverflowUsers answer above, this information was found in [tfs_DefaultCollection].dbo.TreeNodes table;
select * from [tfs_DefaultCollection].dbo.[TreeNodes] where parentID=0 and fDeleted=0
The Column CssNodeID is the ID we are looking for to make sense out of the FullPath
CoolBranchName da3da7cf-80b5-4385-b3dc-ebb3088f3c01
However, this presents us with our next challenge regarding the TFS Databases. A lot of information is encoded and\or embedded so we need to manipulate a few things to get what we are after.
In this instance, the part of the [tfs_DefaultCollection].dbo.tbl_Version.ParentPath or [tfs_DefaultCollection].dbo.tbl_Version.FullPath value that contains the Branch info.
This ugly little diddy right here extracts the ID portion of the ParentPath field value and replaces all the Double-Quotes with Hyphens which gives us an Id value we can use to query [Tfs_DefaultCollection].dbo.TreeNodes
SUBSTRING(
REPLACE( v.ParentPath, '$\', ''),
CHARINDEX( '\', REPLACE( v.ParentPath, '$\', '') ),
( LEN( v.ParentPath ) - CHARINDEX( '\', REPLACE( v.ParentPath, '$\', '') ) )
)
Putting all of this together in pursuit of a Query to Fetch The Last [X] Check-In details results in the following;
select top 10
c.CreationDate,
c.Comment,
u.DisplayName as CommittingUser,
TN.Name as BranchName,
SUBSTRING(
REPLACE( v.ParentPath, '$\', ''),
CHARINDEX( '\', REPLACE( v.ParentPath, '$\', '') ),
( LEN( v.ParentPath ) - CHARINDEX( '\', REPLACE( v.ParentPath, '$\', '') ) )
) as ChangedFile
from tbl_changeset as c
JOIN tbl_IdentityMap IM
ON C.OwnerID = IM.localId
JOIN [Tfs_Configuration].dbo.tbl_Identity u
ON IM.MasterID = u.Id
JOIN dbo.tbl_Version as v
ON v.Versionfrom = c.ChangeSetId
LEFT JOIN dbo.TreeNodes TN with(nolock)
ON TN.CssNodeId = REPLACE(
SUBSTRING(
REPLACE( v.ParentPath, '$\', ''),
0,
CHARINDEX( '\', REPLACE( v.ParentPath, '$\', '') )
),
'"', '-'
)
AND parentID=0
AND fDeleted=0
Order by c.CreationDate desc
Note that I included the DB qualifiers for all the queries leading up to the final query to provide context on where tables of interest are located.

As a workaround how about the below query.. But i think it is returning me the wrong comments.. not sure why.
SELECT top 10
C.ChangeSetId,
V.FullPath,
V.ParentPath,
REPLACE(V.ChildItem,'\','') as [FileName],
C.CreationDate,
I.DisplayName,
C.Comment
FROM tbl_Version(nolock) V
INNER JOIN tbl_File (nolock) F ON V.ItemId = F.ItemId
INNER JOIN tbl_Changeset (nolock) C ON V.VersionTo = C.ChangeSetId
INNER JOIN tbl_Identity (nolock) I ON C.CommitterId = I.IdentityId
where v.ParentPath like '$\' + (select name from [TfsWorkItemTracking].[dbo].[treenodes] where parentid=0 and fdeleted=0 and id=524) + '\%'
order by C.CreationDate desc
Thanks to mark.crockett for posting the above query # http://social.msdn.microsoft.com/Forums/en-US/tfsreporting/thread/32d2c27e-825b-43bb-b156-36048a3e70cb/

If you have access to the SQL server that hosts TFS database the db you have to look is TFSWarehouse, then you can look for the tables Work Item,tbl_Changeset,tbl_Identity,tbl_Version etc. from where you can pull some information.
Thnks.

Related

How to show multiple columns in a single column in SQL?

I have a table attendee, when joining table attendee with table Session, attendee can attend many sessions. So when showing the attendees and what sessions they attended, I am getting multiple rows of the same Attendee, example :
John Doe-BMW Conference
John Doe-Blockchain conference
Jane Doe-blabla
John Doe- Mercedess
Is there a way in sql to display
John Doe- BMW Conference,Mercedes,Block chain?
SELECT Distinct
attendee.Id, attendee.Firstname, attendee.PhoneNumber,
attendee.Email,attendee.Town, attendee.BloodType, session.Id ,
session.LocationId , session.Name as SessionName , location.Id ,
location.Name as Location_Name , sessionattended.SessionAttendedId,
sessionattended.SessionId, sessionattended.AttendeeId,
attendee.Lastname
FROM `session`, `attendee`, `sessionattended`, `location`
WHERE attendee.Id = sessionattended.AttendeeId
and session.Id = sessionattended.SessionId
and session.LocationId = location.Id;
use GROUP_CONCAT MySQL (available since a long time)
or STRING_AGG MSSQL (available in version 2017 and later)
for a comparison of both, see: https://database.guide/mysql-group_concat-vs-t-sql-string_agg/
Google will find info on how to do this in other DBMS's, or even how to do it 'the old way', like here: GROUP BY to combine/concat a column
Try this. Basically the idea is to use FOR XML PATH for this type of result.
SELECT Distinct
a.Id, a.Firstname, a.PhoneNumber, a.Email,a.Town, a.BloodType,
all_conferences = STUFF((SELECT ',' + CAST(s1.Name as Varchar)
FROM sessionattended sa1
JOIN Session s1 ON sa1.SessionId = s1.Id
WHERE sa1.AttendeeId = sa.AttendeeId FOR XML PATH('') ), 1, 1, '')
FROM `session` s
JOIN `sessionattended` sa ON sa.SessionId = s.Id
JOIN `attendee` a ON a.Id = sa.AttendeeId
JOIN `location` l ON s.LocationId = l.Id

Is there an alternative for XML PATH in SQL

I am developing a clinic management application.
In that application there is a part where doctors choose what they use up in each service they provide.
For example, when a doctor examines a patient, a pair of gloves and wooden stick are used and disposed of.
I use a trick that is simply, I create a string in the service table, that string has the IDs separated with comma (something like that 1,3,7,) and it works fine except for one case.
That case is when I want to display the used up item names as one column for multiple services.
I get items of service one plus service two and so on as one string for all service.
Is there any way I can solve that?
I know it sounds complicated but If it works it will many other you read this.
The way I use to join is:
on CHARINDEX(CAST(TblSupply.IDSupply as varchar(10)), TblService.UsedSupplyIDs) > 0
Simply I cast the Used Item ID TblSupply.IDSupply as string then check if it exists in the service table.
When I display as separate columns, it works fine but I get multiple rows for the same service as follows:
Select
TblService.ServiceName,
TblSupply.SupplyName
from
TblService
left join TblSupply on CHARINDEX(CAST(TblSupply.IDSupply as varchar(10)), TblService.UsedSupplyIDs) > 0
e.g.
_____________________________________________
|TblService.ServiceName|TblSupply.SupplyName |
|Patient examination |Glove |
|Patient examination |wood stick |
|Patient examination |thermometer |
|Sonar examination |Glove |
|Sonar examination |lubricating Gel |
|Consultation |Glove |
|______________________|_____________________|
I want to get
________________________________________________________
|TblService.ServiceName|xxxxx |
|Patient examination |Glove ,wood stick , thermometer |
|Sonar examination |Glove,lubricating Gel |
|Consultation |Glove |
The code I made
Select
TblService.ServiceName,TempTable.SupplyList
from
TblService
left join (Select TblService.IDService As IDService,
STUFF((Select ', ' + TblSupply.SupplyName
FROM
TblService
left join TblSupply on CHARINDEX(CAST(TblSupply.IDSupply as varchar(10)), TblService.UsedSupplyIDs) > 0
FOR XML PATH('')), 1, 1, '') as SupplyList
FROM
TblService
GROUP BY
TblService.IDService
) as TempTable on TempTable.IDService=TblService.IDService
I tried
Select
TblPatientService.IDPatientService,
TblService.ServiceName,
TempTable.SupplyList
from
TblPatientService
left Join TblService On TblService.IDService = TblPatientService.IDService
left join (Select TblPatientService.IDPatientService As IDPatientService
STUFF((Select ', ' + TblSupply.SupplyName
FROM
TblPatientService
left join TblService on TblService.IDService = TblPatientService.IDService
left join TblSupply on CHARINDEX(CAST(TblSupply.IDSupply as varchar(10)), TblService.UsedSupplyIDs) > 0
WHERE
TblPatientService.IDService = TblService.IDService
FOR XML PATH('')), 1, 1, '') as SupplyList
FROM
TblPatientService
left Join TblService On TblService.IDService = TblPatientService.IDService
GROUP BY
TblPatientService.IDPatientService
) as TempTable on TempTable.IDPatientService = TblPatientService.IDPatientService
What I really get
|TblService.ServiceName|xxxxx
|Patient examination |Glove ,wood stick , thermometer,Glove,lubricating Gel,Glove,lubricating Gel |
|Sonar examination |Glove ,wood stick , thermometer,Glove,lubricating Gel,Glove,lubricating Gel |
|Consultation |Glove ,wood stick , thermometer,Glove,lubricating Gel,Glove,lubricating Gel |
In other words I get all the used items for all services as if they used for one service for all displayed.
Since SQL Server 2017, you can use STRING_AGG. Somtehing like :
SELECT TblPatientService.IDPatientService AS IDPatientService,
STRING_AGG(TblSupply.SupplyName, ', ') AS SupplyList
FROM TblPatientService
LEFT OUTER JOIN TblService ON TblService.IDService = TblPatientService.IDService
LEFT OUTER JOIN TblSupply ON CHARINDEX(CAST(TblSupply.IDSupply AS VARCHAR(10)), TblService.UsedSupplyIDs) > 0
GROUP BY TblPatientService.IDPatientService;
To replace XML stuff !
This is too long for a comment.
I would strongly suggest fixing your data model. Storing delimited lists in database columns is a typical design antipattern, that will backfire in different ways (complexity, efficiency, maintenance, data integrity). You can ha have a look at this famous SO question for more details.
As an exemple: your current join condition will not do what you expect for some supply ids that are more than one digit long (typically, 1 would match 10).
You should normalize your model and have a separate table to store the N-M relationship between services and supplies, with one tuple per row.

What Is Wrong With This FOR XML PATH

I can't seem to figure out why this won't work in MS SQL Server. It seems to not group the lines. Specifically I see:
1036 SC
1036 S1
1094 VO
1094 V1
1094 V2
When I expect to see:
1036 SC,S1
1094 VO,V1,V2
Can someone see something wrong with the syntax?
SELECT DISTINCT oa.acct_cd AS [Account],
STUFF((SELECT ',' + CASE WHEN o.trans_type like 'BUY%' then 'buy of ' else 'sell of ' end + s.ticker AS [text()]
FROM [dbo].[synCRtblTS_ORDER] o INNER JOIN [dbo].[synCRtblCSM_SECURITY] s
ON o.SEC_ID = s.SEC_ID
WHERE o.ORDER_ID = oa.ORDER_ID AND o.status IN ('OPEN','WORK','PENDING')
FOR XML PATH('')), 1, 1, '') [buy/sell]
FROM [dbo].[synCRtblTS_ORDER_ALLOC] oa INNER JOIN tblPortfolio p
ON oa.ACCT_CD = p.Account INNER JOIN tblInvestmentObjective io
ON io.Code = p.InvestmentObjective
WHERE p.AsOfDate = (SELECT AsOfDate FROM tblDateAsOf) and io.CashMgmtStrategy IN ('SC','VO')
GROUP BY oa.ORDER_ID, oa.acct_cd
order by 1
The Information you give is not enough... Within your STUFF you create (and concatenate) string which should contain "buy of" or "sell of". You are missing this information in your output.
It's guessing that your SC, S1, VO values are CashMgmtStrategy entries. You are not concatenating them...
Without deeper knowledge of your tables I cannot solve your problem, but here you'll find a working example of concatenation via FOR XML and STUFF
This code will list all table's names and their columns in a comma delimited list.
SELECT DISTINCT tbls.name AS TableName,
STUFF(
(
SELECT ', ' + cols.name
FROM sys.columns AS cols
WHERE cols.object_id = tbls.object_id
FOR XML PATH('')
), 1, 2, '') AS ColumnList
FROM sys.tables AS tbls

Check special character in sql view

Hi i am in fix for a particular scenario, i have a view which is created by joining multiple tables, the requirement is that i have to find whether the columns in that view will return special character.
SELECT SI.ShipmentId,
CASE
WHEN SA.AddressType = 1 THEN 'SH'
ELSE 'CN'
END AS AddressType,
SI.Pieces,
SI.PalletCount,
SI.Weight,
SI.UserDescription,
SI.Class,
SA.CompanyName,
SA.Street,
SA.City,
SA.State,
SA.ZipCode,
CASE
WHEN SA.Country = 1 THEN 'USA'
WHEN SA.Country = 2 THEN 'CANADA'
END AS Country,
SA.ContactPerson,
Cast(Replace(Replace(Replace(Replace(SA.Phone, ')', ''), '(', ''), '-', ''), ' ', '') AS VARCHAR(25)) AS Phone,
S.PoNo,
S.EstimatedDueDate,
Cast(S.ShipmentReadyTime AS VARCHAR(10)) AS ShipmentReadyTime,
Cast(S.ShipmentCloseTime AS VARCHAR(10)) AS ShipmentCloseTime,
B.BOLNumber,
S.HazMatEmergencyNo
FROM CarrierRate.Shipment AS S
INNER JOIN CarrierRate.BOL AS B
ON B.ShipmentId = S.ID
INNER JOIN CarrierRate.ShipmentItems AS SI
ON SI.ShipmentId = S.ID
INNER JOIN CarrierRate.ShipmentAddresses AS SA
ON SA.ShipmentId = S.ID
INNER JOIN CarrierRate.Carriers AS C
ON C.ID = S.CarrierId
WHERE ( SI.AccessorialId = 1 )
AND ( SA.AddressType IN ( 1, 2 ) )
This is that view, i just want to know what all columns will have special character as its data.
For E.g: i have SA.CompanyName as one of the column, i have to check whether that column can be filled with special characters?
Please let me know the probable solutions, i am clueless.
You need to look at the column types of the tables/columns/expressions which contribute to the columns of the view you are interested in. Assuming they are defined as some form of text or varchar then they CAN contain special characters, unless there exists some form of constraint on those columns/tables.

SQL Join then combine columns from the result

So I have two db2 tables. One contains work order information like id, requester name, user, description, etc. Second table that has notes, which is keyed to the id of the other table. The notes field is a 255 text field (Yeah don't suggest changing it, I have no control over it). So there could be multiple results, or none, in the note field depending on obviously how many notes there are.
I have a query which fetches the results. The problem is that I am getting multiple results form the join because there are multiple entries.
So my question is how do I concat/merge the results from the notes table into one field for every result? Thanks
Code:
SELECT
p.ABAANB AS WO_NUMBER,
p.ABAJTX AS Description,
i.AIAKTX as Notes
FROM
htedta.WFABCPP p LEFT JOIN HTEDTA.WFAICPP i
ON i.AIAANB = p.ABAANB
WHERE
p.ABABCD = 'ISST' AND p.ABAFD8 = 0
Have you tried LISTAGG
https://www.ibm.com/developerworks/mydeveloperworks/blogs/SQLTips4DB2LUW/entry/listagg?lang=en
It will allow you to merge all those pesky fields that are causing the additional records... Something like this...
SELECT p.ABAANB AS WO_NUMBER, p.ABAJTX AS Description, LISTAGG(i.AIAKTX, ' ') as Notes
FROM htedta.WFABCPP p
LEFT JOIN HTEDTA.WFAICPP i
ON i.AIAANB = p.ABAANB
WHERE p.ABABCD = 'ISST'
AND p.ABAFD8 = 0
GROUP BY p.ABAAMB, p.ABAJTX
What version of DB2 are you on? If you're using DB2 Linux/Unix/Windows (LUW), then this should work for you:
SELECT p.ABAANB AS WO_NUMBER,
p.ABAJTX AS Description,
,SUBSTR(
xmlserialize(
xmlagg(
xmltext(
concat(',' , TRIM(i.AIAKTX))
)
) AS VARCHAR(4000)
)
,2) AS NOTES
FROM htedta.WFABCPP p
LEFT JOIN HTEDTA.WFAICPP i
ON i.AIAANB = p.ABAANB
WHERE p.ABABCD = 'ISST'
AND p.ABAFD8 = 0
GROUP BY p.ABAANB,
p.ABAJTX
If you are running DB2 at least 9.7, you should be able to use the XMLAGG function similar to this
WITH CombinedNotes( aiaanb, aiaktx) AS (
SELECT aiaanb
, REPLACE( REPLACE(
CAST( XML2CLOB(
XMLAGG( XMLELEMENT(
NAME 'A'
, aiaktx
))
) AS VARCHAR( 3000))
, '<A>',''), '</A>', '')
FROM Htedta.WfaIcpp)
SELECT p.ABAANB AS WO_NUMBER, p.ABAJTX AS Description, i.AIAKTX as Notes
FROM htedta.WFABCPP p
LEFT JOIN CombinedNotes i
ON i.AIAANB = p.ABAANB
WHERE p.ababcd = 'ISST'
AND p.abafd8 = 0;
If you have an earlier version of DB2, or your login for some reason does not permit the XML functions, you can solve the problem with a recursive query. Both techniques are described in the following blog
http://ibmmainframes.com/about44805.html