Please start any new threads on our new
site at https://forums.sqlteam.com. We've got lots of great SQL Server
experts to answer whatever question you can come up with.
| Author |
Topic |
|
nmiddleweek
Starting Member
3 Posts |
Posted - 2008-05-12 : 09:36:03
|
| Hello,My SQL knowledge is limited so if I get stuff wrong then correct me... but I can imagine this task will be quite testing...I am working on a system that logs ([Audit] table) the changes to fields on some tables using a Trigger on UPDATE. I need to produce a 'quick' report that returns the date when the tables overallStatus field was set to 1.In the [Audit] table I can find all the field changes for the record in question using this SQL...select *from auditwhere rowid = 1309606order by auditID ascMy problem is filtering this data. The fields I need are formatted as below, see records returned, in ASC order...audit.AuditID = 2652583audit.OperationTime = 2008-04-24 15:12:07.740audit.ColumnDetail = 'estimatedProductionPriceactualProductionCost'audit.EditDetail = '0.00000.0000'audit.AuditID = 2658460audit.OperationTime = 2008-04-25 10:51:47.930audit.ColumnDetail = 'overallStatusInsertionStatus'audit.EditDetail = '05'audit.AuditID = 2665723audit.OperationTime = 2008-04-25 22:06:50.200audit.ColumnDetail = 'overallStatusdespatchDateInsertionStatus'audit.EditDetail = '1 3'audit.AuditID = 2711092audit.OperationTime = 2008-04-30 17:22:12.593audit.ColumnDetail = 'overallStatusInsertionStatus'audit.EditDetail = '34'audit.AuditID = 2713217audit.OperationTime = 2008-04-30 20:46:34.817audit.ColumnDetail = 'clientOrderNumber'audit.EditDetail = 'PAT12P7640'The funny character, , is ASCII 127.So need to find when 1309606's overallStatus was changed to 1. Manually looking at the data, I can see overallStatus was modified in 3 of the above 5 [Audit] records. It started life as 0, then went to 1 and then to 3. I'm aware that I need to look at the previous Audits date for when it was changed to the value I'm looking for... So it was changed to 1 on 2008-04-25 10:51:47.930.What is the best way to approach this problem? I'm hoping to use T-SQL only and not have to use an external scripting language, unless I can embed vbscript or jscript inside a T-SQL function and then use arrays, etc?Somehow I need to convert the ASCII(127) seperated list of fieldname into an array or list, find the index of the fieldname 'overallStatus' and then lookup that value in the datafield.Hope that makes sense and any help would be great!Cheers,Nick |
|
|
visakh16
Very Important crosS Applying yaK Herder
52326 Posts |
Posted - 2008-05-12 : 10:18:23
|
Make a UDF like this:-CREATE FUNCTION GetValues(@ColString varchar(max),@ValString varchar(max),@Delimiter char(1))RETURNS @Results TABLE(ID int IDENTITY(1,1),Column varchar(100),Value varchar(100))ASDECLARE @Col varchar(100),@Val varchar(100)WHILE @ColString IS NOT NULL AND @ValString IS NOT NULLBEGINSELECT @Col=CASE WHEN CHARINDEX(CHAR(127),@ColString) >0 THEN LEFT(@ColString,CHARINDEX(CHAR(127),@ColString)-1) ELSE @ColString END, @Val=CASE WHEN CHARINDEX(CHAR(127),@ValString) >0 THEN LEFT(@ColString,CHARINDEX(CHAR(127),@ValString)-1) ELSE @ValString ENDINSERT INTO @Results (Column,Value)SELECT @Col,@ValSELECT @ColString=CASE WHEN CHARINDEX(CHAR(127),@ColString) >0 THEN SUBSTRING(@ColString,CHARINDEX(CHAR(127),@ColString)+1,LEN(@ColString)) ELSE NULL END, @ValString=CASE WHEN CHARINDEX(CHAR(127),@ValString) >0 THEN SUBSTRING(@ValString,CHARINDEX(CHAR(127),@ValString)+1,LEN(@ValString)) ELSE NULL ENDENDGO And try using it like thisDECLARE @RowID=1309606;With CTE (RowNo,AuditID,OpeartionTime,Value) AS(SELECT ROW_NUMBER() OVER (ORDER BY AuditID),a.AuditID,a.OperationTime,b.ValueFROM Audit aCROSS APPLY (SELECT Value FROM GetValues(a.ColumnDetail,a.EditDetail,CHAR(127) WHERE Column='overallStatus') bWHERE RowId=@RowID)SELECT c1.OpeartionTimeFROM CTE c1INNER JOIN CTE c2ON c2.RowNo=c1.RowNo + 1WHERE c2.Value=1 |
 |
|
|
nmiddleweek
Starting Member
3 Posts |
Posted - 2008-05-12 : 12:09:31
|
| visakh16,Thanks for you reply on this - not that I understand it all but I get the idea and it that looks like what I need. So I convert the strings to a 2 col temp table and then use that for the lookups.I've copied the code into SQL Management Studio and parsed it. I got an error at Column and Value varchar(100) cause of reserved words. I'm now getting an error on this line..DECLARE @Col varchar(100), @Val varchar(100)Msg 156, Level 15, State 1, Procedure fnc_Split, Line 17Incorrect syntax near the keyword 'DECLARE'.I've tried looking at other functions that return temp tables but I can't find any that define the fields like you have, they just return columns from select statements and not dynamically INSERT the data to the returned table.I'm sure it's something obvious?Thanks,Nick |
 |
|
|
visakh16
Very Important crosS Applying yaK Herder
52326 Posts |
Posted - 2008-05-12 : 12:31:54
|
quote: Originally posted by nmiddleweek visakh16,Thanks for you reply on this - not that I understand it all but I get the idea and it that looks like what I need. So I convert the strings to a 2 col temp table and then use that for the lookups.I've copied the code into SQL Management Studio and parsed it. I got an error at Column and Value varchar(100) cause of reserved words. I'm now getting an error on this line..DECLARE @Col varchar(100), @Val varchar(100)Msg 156, Level 15, State 1, Procedure fnc_Split, Line 17Incorrect syntax near the keyword 'DECLARE'.I've tried looking at other functions that return temp tables but I can't find any that define the fields like you have, they just return columns from select statements and not dynamically INSERT the data to the returned table.I'm sure it's something obvious?Thanks,Nick
i missed a return at the endCREATE FUNCTION GetValues(@ColString varchar(max),@ValString varchar(max),@Delimiter char(1))RETURNS @Results TABLE(ID int IDENTITY(1,1),Column varchar(100),Value varchar(100))ASBEGINDECLARE @Col varchar(100),@Val varchar(100)WHILE @ColString IS NOT NULL AND @ValString IS NOT NULLBEGINSELECT @Col=CASE WHEN CHARINDEX(CHAR(127),@ColString) >0 THEN LEFT(@ColString,CHARINDEX(CHAR(127),@ColString)-1) ELSE @ColString END, @Val=CASE WHEN CHARINDEX(CHAR(127),@ValString) >0 THEN LEFT(@ColString,CHARINDEX(CHAR(127),@ValString)-1) ELSE @ValString ENDINSERT INTO @Results (Column,Value)SELECT @Col,@ValSELECT @ColString=CASE WHEN CHARINDEX(CHAR(127),@ColString) >0 THEN SUBSTRING(@ColString,CHARINDEX(CHAR(127),@ColString)+1,LEN(@ColString)) ELSE NULL END, @ValString=CASE WHEN CHARINDEX(CHAR(127),@ValString) >0 THEN SUBSTRING(@ValString,CHARINDEX(CHAR(127),@ValString)+1,LEN(@ValString)) ELSE NULL ENDENDRETURNENDGO |
 |
|
|
RyanRandall
Master Smack Fu Yak Hacker
1074 Posts |
Posted - 2008-05-12 : 12:59:46
|
I've been having fun with this .I've no idea if it will be useful, and the performance is probably horrendous, but this is what I came up with...  -- Structure and Datadeclare @audit table (AuditID int, OperationTime datetime, ColumnDetail varchar(100), EditDetail varchar(100))insert @audit select 2652583, '2008-04-24 15:12:07.740', 'estimatedProductionPrice' + char(127) + 'actualProductionCost' + char(127), '0.0000' + char(127) + '0.0000' + char(127)union all select 2658460, '2008-04-25 10:51:47.930', 'overallStatus' + char(127) + 'InsertionStatus' + char(127), '0' + char(127) + '5' + char(127)union all select 2665723, '2008-04-25 22:06:50.200', 'overallStatus' + char(127) + 'despatchDate' + char(127) + 'InsertionStatus' + char(127), '1' + char(127) + char(127) + '3' + char(127)union all select 2711092, '2008-04-30 17:22:12.593', 'overallStatus' + char(127) + 'InsertionStatus' + char(127), '3' + char(127) + '4' + char(127)union all select 2713217, '2008-04-30 20:46:34.817', 'clientOrderNumber' + char(127), 'PAT12P7640' + char(127)-- Inputsdeclare @Col varchar(30); set @Col = 'overallStatus';declare @Val varchar(30); set @Val = '1';-- Calculation; withNumbers as (SELECT distinct Number as i FROM Master.dbo.spt_values where number between 1 and 20),a as (select AuditID, OperationTime, replace(char(127) + ColumnDetail, char(127), '" /><col name="') cols, replace(char(127) + EditDetail, char(127), '" /><val name="') vals from @audit),b as (select AuditID, OperationTime, cast(substring(cols, 5, len(cols)-15) as xml) colXml, cast(substring(vals, 5, len(vals)-15) as xml) valXml from a),c as (select AuditID, OperationTime, colXml.query('(/col[position() = sql:column("c.i")])[1]').value('(//@name)[1]', 'varchar(50)') Col, valXml.query('(/val[position() = sql:column("c.i")])[1]').value('(//@name)[1]', 'varchar(50)') Val from b cross join Numbers c),d as (select * from c where Col = @Col)select a.*, b.OperationTime as PreviousOperationTime, b.val as PreviousValfrom d a outer apply (select top 1 * from d where Col = a.Col and OperationTime < a.OperationTime order by OperationTime desc) bwhere a.Val = @Val/* ResultsAuditID OperationTime Col Val PreviousOperationTime PreviousVal----------- ----------------------- ------------------- ---------- ----------------------- -------------2665723 2008-04-25 22:06:50.200 overallStatus 1 2008-04-25 10:51:47.930 0*/Edit: a few minor tweaks.Ryan Randall Solutions are easy. Understanding the problem, now, that's the hard part. |
 |
|
|
nmiddleweek
Starting Member
3 Posts |
Posted - 2008-05-12 : 13:00:28
|
Hello,Thanks again... that's working ok now... I'm now using the second part to call the GetValues function... I had to split the top line into seperate DECLARE and SET statements but I'm now getting an Incorrect Syntax near the keyword WHERE after the CROSS APPLY...I've changed Column to fldColumn to match my change in the function created so it's not that. See below for code I'm using...DECLARE @RowID intSET @RowID = 1309606;With CTE (RowNo,AuditID,OpeartionTime,Value) AS ( SELECT ROW_NUMBER() OVER (ORDER BY AuditID), a.AuditID, a.OperationTime, b.fldValue FROM Audit a CROSS APPLY (SELECT fldValue FROM GetValues(a.ColumnDetail,a.EditDetail,CHAR(127) WHERE fldColumn = 'overallStatus') b --ERRORS HERE WHERE RowId = @RowID )SELECT c1.OperationTimeFROM CTE c1INNER JOIN CTE c2ON c2.RowNo=c1.RowNo + 1WHERE c2.Value=1Cheers,Nick |
 |
|
|
RyanRandall
Master Smack Fu Yak Hacker
1074 Posts |
Posted - 2008-05-12 : 13:04:31
|
| FROM GetValues(a.ColumnDetail,a.EditDetail,CHAR(127)) <-- need extra bracket?Ryan Randall Solutions are easy. Understanding the problem, now, that's the hard part. |
 |
|
|
|
|
|
|
|