I know that there are many questions on this topic, but no one seem to works for my problem
Shortly, I want to merge horizontal an unknown number of result sets as in the following example
Result 1:
Name |sum1 |sum2
________________
name1| 0.5 |0.1
name2| 0.6 |0.2
Result 2:
Name |sum1 |sum2
________________
name1| 1.5 |0.7
name2| 1.6 |0.9
.
.
.
Result n:
Name |sum1 |sum2
________________
name1| 7.5 |9.7
name2| 8.6 |5.9
Finally :
Name |sum1 |sum2| sum1 | sum2|.......| sum1|sum2
________________________________________
name1| 0.5 |0.1 | 1.5 | 0.7 |.......| 7.5 |9.7
name2| 0.6 |0.2 | 1.6 | 0.9 |.......| 8.6 |5.9
The column "Name" is exactly the same in all of the result.
Think you guys could help out?
You would use join:
select r1.name, r1.sum1, r1.sum2, r2.sum1, r2.sum2, r3.sum1, r3.sum2
from result1 r1 join
result2 r2
on r1.name = r2.name join
results r3
on r1.name = r3.name
You would need to continue this for each result set.
Now, having an unknown number of result sets makes this more complicated. That simply requires generating a dynamic SQL statement, based on the same logic.
Quick stored procedure to dynamically build your query string and execute it. You can control the execute with the first input #in_run_query.
CREATE PROCEDURE dynamic_sql_query
#in_run_query INT
, #in_count_results_sets INT
AS
BEGIN
IF #in_count_results_sets IS NULL
EXIT
IF TRY_CONVERT(INT,#in_count_results_sets) IS NULL
EXIT
IF #in_count_results_sets < 2
BEGIN
SELECT 'Counter must be between 2 and 100'
EXIT
END
IF #in_count_results_sets > 100
BEGIN
SELECT 'Build a better database'
EXIT
END
DECLARE #sql_string NVARCHAR(MAX) , #counter INT = 2
SET #select = 'SELECT r1.name, r1.sum1, r1.sum2'
SET #from = 'FROM result1 AS r1'
LOOP:
SET #prefix = 'r' + CAST(#counter AS String)
SET #full_name = 'result' + CAST(#counter AS String)
-- select
SET #select = #select + ', ' + #prefix + '.name, ' + #prefix + '.sum1, ' + #prefix + '.sum2'
-- from
SET #from = #from + ' join ' + #full_name + ' AS ' + #prefix + ' on r1.name = ' + #prefix + '.name'
IF #counter = #in_count_results_sets
GOTO AppendStrings
#counter = #counter + 1
GOTO LOOP
AppendStrings:
SET #sql_string = #select + ' ' + #from + ';'
IF #in_run_query <> 1
BEGIN
SELECT #sql_string
EXIT
END
EXECUTE sp_executesql #sql_string
END
Related
I have created a DB Mail alert that sends out a HTML formatted table showing the pass or fail status of my SQL agents.
The alert works well, but the user has request an additional change where they want conditional formating on Pass/Fail status of the data, where failed status is to be highlighted RED and pass status to be highlighted GREEN.
Is this possible to achieve to in SQL using DB Mail and HTML formatting?
A few forums have stated that JavaScript may need to be used but I'm not sure if its possible to even us JS in SQL.
My code is below:
----------------------------------------------------------------------------
----------------------------------- Declare Variables ----------------------
----------------------------------------------------------------------------
Declare #email_body nvarchar(max)
Declare #email_profile_name nvarchar(max)
Declare #email_recipients nvarchar(max)
Declare #email_subject nvarchar(max)
Declare #tableHTML nvarchar(MAX) = ''
Declare #Style nvarchar(MAX) = ''
Declare #Textdate nvarchar(max)
DECLARE #crlf nvarchar = CHAR(13)+CHAR(10)
Declare #Server nvarchar(max)
----------------------------------------------------------------------------
--------------------------- Set Varriables (That should not change) --------
----------------------------------------------------------------------------
set #Server = ##SERVERNAME
set #Textdate = cast(getdate() as date)
Set #email_subject = #Textdate + ': Morning SQL Server Checks'
----------------------------------------------------------------------------
----------------------------------- Set Varriables (User Input) ------------
----------------------------------------------------------------------------
--Add other Email addresses as needed. Seperate with Semi-colon (;)
set #email_recipients = 'Email#Email.com'
----------------------------------------------------------------------------
----------------------------------- Create Temp Tables ---------------------
----------------------------------------------------------------------------
IF OBJECT_ID('tempdb..#Results') IS NOT NULL
DROP TABLE #Results
Create table #Results (
[Server] nvarchar(max),
[Entity] nvarchar(max),
[Status] nvarchar(max),
[Message] nvarchar(max),
[Type] nvarchar(max))
----------------------------------------------------------------------------
----------------------------------- Generate Data --------------------------
----------------------------------------------------------------------------
--Gets SQL Agent Results (Script Derived from here:
https://social.msdn.microsoft.com/Forums/sqlserver/en-US/534cc5be-0021-4766-
9eef-92fea819e2e3/script-to-get-sql-server-agent-job-schedule-and-the-last-
run-status?forum=sqldatabaseengine)
Insert into #Results
SELECT ##SERVERNAME as 'Server Name'
,J.Name AS 'Job Name'
--,CASE J.Enabled WHEN 1 THEN 'Yes' WHEN 0 THEN 'No' END as 'Job
Enabled'
,CASE WHEN LASTRUN.run_status = 0 THEN 'Failed'
WHEN LASTRUN.run_status = 1 THEN 'Succeeded'
WHEN LASTRUN.run_status = 2 THEN 'Retry'
WHEN LASTRUN.run_status = 3 THEN 'Cancelled'
ELSE 'Unknown' END as 'Last Run Status'
,LASTRUN.message as 'Last Run Message'
,'SQL Agent Jobs' as 'Type'
FROM msdb.dbo.sysjobs J LEFT OUTER JOIN msdb.dbo.sysjobschedules JS ON
J.job_id = JS.job_id
LEFT OUTER JOIN msdb.dbo.sysschedules S ON JS.schedule_id = S.schedule_id
LEFT OUTER JOIN (SELECT J1.job_id
,J1.RUN_DURATION
,J1.run_date
,J1.run_time
,J1.message
,J1.run_status
FROM msdb.dbo.sysjobhistory J1
WHERE instance_id = (SELECT MAX(instance_id)
FROM msdb.dbo.sysjobhistory J2
WHERE J2.job_id = J1.job_id)) LASTRUN ON J.job_id = LASTRUN.job_id
where J.Enabled = 1 --Only check for agents that have been enabled
--------------------------------------------------------------------------
----------------------------------- Generate Email -------------------------
----------------------------------------------------------------------------
--Set Style (CSS)
SET #Style += +N'<style type="text/css">' + N'.tg {border-
collapse:collapse;border-spacing:0;border-color:#aaa;}'
+ N'.tg td{font-family:Arial, sans-serif;font-size:14px;padding:10px 5px;border-style:solid;border-width:1px;overflow:hidden;word-break:normal;border-color:#aaa;color:#333;background-color:#fff;}'
+ N'.tg th{font-family:Arial, sans-serif;font-size:14px;font-weight:normal;padding:10px 5px;border-style:solid;border-width:1px;overflow:hidden;word-break:normal;border-color:#aaa;color:#fff;background-color:#f38630;}'
+ N'.tg .tg-9ajh{font-weight:bold;background-color:#68cbd0}' + N'.tg .tg-hgcj{font-weight:bold;text-align:center}'
+ N'</style>';
--Set Email Output (HTML Layout)
Set #tableHTML += #Style + #tableHTML + N'<H1 style="color:Blue;">' +
#Textdate + ': Morning SQL Server Checks</H1>' +
N'<H2>' + #Server + '</H2>' +
N'<H3>Databases</H3>' +
+ N'<table class="tg">' --DEFINE TABLE
-- Define Headers for Database Check
+ N'<tr>'
+ N'<H3>SQL Agents</H3>' +
+ N'<table class="tg">' --DEFINE TABLE
+ N'<tr>'
+ N'<td class="tg-9ajh">Server</td>'
+ N'<td class="tg-9ajh">Entity</td>'
+ N'<td class="tg-9ajh">Status</td>'
+ N'<td class="tg-9ajh">Message</td>'
+ N'<td class="tg-9ajh">Type</td></tr>'
-- Define data for SQL Agent and cast to xml
+ Cast((
Select td = isnull([Server],'###')
,''
,td = isnull([Entity],'###')
,''
,td = isnull([Status],'###')
,''
,td = isnull([Message],'###')
,''
,td = isnull([Type],'###')
,''
from #Results
where [type] = 'SQL Agent Jobs' FOR
XML PATH('tr') ,
TYPE
) AS NVARCHAR(MAX))
+ N'</table>';
-- Send the Email
EXEC msdb.dbo.sp_send_dbmail
#profile_name = 'Outlook Support Profile',
#recipients = #email_recipients,
#body = #tableHTML,
#body_format = 'HTML',
#subject = #email_subject
----------------------------------------------------------------------------
----------------------------------- Cleanup --------------------------------
----------------------------------------------------------------------------
drop table #Results
I hope the code is clear enough and makes sense.
Thanks you
Anthony
I do something similar with my dbmail audit emails to differentiate between production and non-production instances.
The method I use is to predefine the style information and then use a unique value in the body string to identify where the style needs to be applied. In your case the unique values we can use are <td>Failed and <td>Succeeded. By doing a replace on those values to a version that includes the style, you should get a table with your conditional formatting.
I made the following two changes to your script and ran it against one of my test instances. It looks like it should get you where you want.
First, update the style section:
--Set Style (CSS)
SET #Style += +N'<style type="text/css">' + N'.tg {border-
collapse:collapse;border-spacing:0;border-color:#aaa;}'
+ N'.tg .green{background-color: green; color:white;}'
+ N'.tg .red{background-color: red; color:white;}'
+ N'.tg td{font-family:Arial, sans-serif;font-size:14px;padding:10px 5px;border-style:solid;border-width:1px;overflow:hidden;word-break:normal;border-color:#aaa;color:#333;background-color:#fff;}'
+ N'.tg th{font-family:Arial, sans-serif;font-size:14px;font-weight:normal;padding:10px 5px;border-style:solid;border-width:1px;overflow:hidden;word-break:normal;border-color:#aaa;color:#fff;background-color:#f38630;}'
+ N'.tg .tg-9ajh{font-weight:bold;background-color:#68cbd0}' + N'.tg .tg-hgcj{font-weight:bold;text-align:center}'
+ N'</style>';
After #tableHTML is built, add a REPLACE to shove the style formatting into the generated table:
SELECT #tableHTML = REPLACE(REPLACE(#tableHTML,N'<td>Failed',N'<td class="Red">Failed'),N'<td>Succeeded',N'<td class="green">Succeeded')
My print statement fails each time and so does my exec, anytime I try to run this statement it just tells me command completed successfully. I added the print statement to try to see what was actually being executed, but I am still mind-blown on this. Can someone here please help me?
Shouldn't the Print statement at least show me what I am trying to run? If I print each variable individually before trying to run the update it shows the correct value, so I can only assume it is something way wrong with my update statement?
Declare #fulldata varchar(30), #rsi varchar(50), #employeename varchar(50), #email varchar(50), #rsi2 varchar(50), #email2 varchar(50),
#rsiID varchar(50), #calldate datetime, #calltime datetime, #orderdate datetime, #email3 varchar(50), #uniqueID int, #sql varchar(max)
Set #fullData = 'tvdb'
Set #rsi = 'Alphabet'
Set #employeename = 'Mike Jones'
Set #email = '123abc#gmail.com'
Set #rsi2 = 'Broccoli'
Set #email2 = 'abc123#gmail.com'
Set #rsiID = 'alt16bc'
Set #calldate = '06/15/2015'
Set #calltime = '12:15:00'
Set #orderdate = '06/16/2015'
Set #email3 = 'pineapple1841#gmail.com'
Set #uniqueID = 172855
Set #sql =
'update '+#fulldata+' '
+ 'set rsi = COALESCE('''+#rsi+''',''''), '
+ 'employeename = COALESCE('''+#employeename+''',''''), '
+ 'email = COALESCE('''+#email+''',''''), '
+ 'rsi2 = COALESCE('''+#rsi2+''',''''), '
+ 'email2 = COALESCE('''+#email2+''',''''), '
+ 'rsiID = COALESCE('''+#rsiID+''',''''), '
+ 'calldate = COALESCE('''+CAST(#calldate As Varchar)+''',''''), '
+ 'calltime = COALESCE('''+CAST(#calltime As Varchar)+''',''''), '
+ 'orderdate = COALESCE('''+CAST(#orderdate As Varchar)+''',''''), '
+ 'email3 = COALESCE('''+#email3+''','''') '
+ 'where uniqueID = '+CAST(#uniqueID As Varchar)+' and '+CAST(#uniqueID As Varchar)+' > 0 '
Print #sql
exec (#sql)
EDIT ---
If I try to insert my statements into a table to check it is null. Which leads me to why is #sql not being assigned?
Insert Into #SqlStatement (sql12) VALUES (#sql)
Select * FROM #SqlStatement
Are you sure you have all lines included here? and you can run it without error?
At least your don't have declaration of #sql.
Even you declare the #sql, this line will give you error:
Set uniqueID = 172855
It should be
Set #uniqueID = 172855
Without assigning values to #uniqueID, your whole #sql is be NULL and print will generate NO output.
update tvdb set rsi = COALESCE('Alphabet',''), employeename = COALESCE('Mike Jones',''), email = COALESCE('123abc#gmail.com',''), rsi2 = COALESCE('Broccoli',''), email2 = COALESCE('abc123#gmail.com',''), rsiID = COALESCE('alt16bc',''), calldate = COALESCE('Jun 15 2015 12:00AM',''), calltime = COALESCE('Jan 1 1900 12:15PM',''), orderdate = COALESCE('Jun 16 2015 12:00AM',''), email3 = COALESCE('pineapple1841#gmail.com','') where uniqueID = 172855 and 172855 > 0
Msg 208, Level 16, State 1, Line 1
Invalid object name 'tvdb'.
To debug your code, you can comment out some lines like:
Set #sql =
'update '+#fulldata+' '
+ 'set rsi = COALESCE('''+#rsi+''',''''), '
---+ 'employeename = COALESCE('''+#employeename+''',''''), '
----+ 'email = COALESCE('''+#email+''',''''), '
----+ 'rsi2 = COALESCE('''+#rsi2+''',''''), '
----+ 'email2 = COALESCE('''+#email2+''',''''), '
----+ 'rsiID = COALESCE('''+#rsiID+''',''''), '
----+ 'calldate = COALESCE('''+CAST(#calldate As Varchar)+''',''''), '
----+ 'calltime = COALESCE('''+CAST(#calltime As Varchar)+''',''''), '
----+ 'orderdate = COALESCE('''+CAST(#orderdate As Varchar)+''',''''), '
----+ 'email3 = COALESCE('''+#email3+''','''') '
----+ 'where uniqueID = '+CAST(#uniqueID As Varchar)+' and '+CAST(#uniqueID As Varchar)+' > 0 '
Print #sql
exec (#sql)
and uncomment one line a time until you find the problematic line.
To catch values and make sure you have a non-null #sql, you need use the COALESCE this way:
Set #sql =
'update '+#fulldata+' ' ...
+ 'email = '''+COALESCE(#email,'')+''','
How can I parameterize the following query? (By the way I'm using a full text indexed table, hence the CONTAINS())
SELECT * FROM Table WHERE CONTAINS(Column, 'cat OR dog')
and ((column NOT LIKE '%[^ cat OR dog]%'));
This didn't work:
DECLARE #term1 VARCHAR(10);
DECLARE #term2 VARCHAR(10);
SET #term1 = 'cat';
SET #term2 = 'dog';
SET #term3 = #term1 + ' ' + 'OR' + ' ' + #term2;
SET #term4 = '[^ #term1 OR #term2 ]' ;
SELECT * FROM table WHERE CONTAINS(column, #term3) <--up to this point works
AND (column NOT LIKE '%[#term4]%'); <--this part doesn't include the second term (#term2)
If you'd like to fiddle with this on your end, my Full Text Indexed table looks like:
animalListID AnimalsList
1 cat dog
2 cat
3 cat dog bird
(basically i need the parameterized version of the SELECT statement which returns the rows with 'cat dog' and 'cat' and NOT 'cat dog bird')
**This is a VERY oversimplified version of my data, but the question is an exact match of the concept I'm trying to achieve. The table will have millions of rows, and many terms in each row.
You should do
SET #term4 = '[^ ' + #term1 + ' OR ' + #term2 + ' ]';
and
column NOT LIKE '%' + #term4 + '%'
Alternatively, you could initialize #term4 to also include the % signs:
SET #term4 = '%[^ ' + #term1 + ' OR ' + #term2 + ' ]%';
and then simplify the LIKE statement to:
column NOT LIKE #term4
Sir My Procedure is
USE [PGATE_GITS]
GO
/****** Object: StoredProcedure [dbo].[usp_GetTimeReport_Weekly1] Script Date: 03/29/2012 15:14:15 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER procedure [dbo].[usp_GetTimeReport_Weekly1]
#pi_empId int,
--#pi_v_ep_id int,
--#pi_ep_id int,
#pi_rptFromDate varchar(10),
#pi_rptToDate varchar(10)
AS
BEGIN
declare #si_sql VARCHAR(1000)
SET #si_sql = 'SELECT EP_FIRST_NAME + '' '' + EP_LAST_NAME as [Employee_Name],'
SET #si_sql = #si_sql + 'CONVERT(VARCHAR(3),CONVERT(VARCHAR(3),
(SUM(DATEPART(HH,CONVERT (VARCHAR,GTT_NO_OF_HOURS,108))) + (SUM(DATEPART(MI,CONVERT (VARCHAR,GTT_NO_OF_HOURS,108)))/60))))+'':''+ CONVERT(VARCHAR(2),CONVERT(VARCHAR(2),
SUM(DATEPART(MI,CONVERT (VARCHAR,GTT_NO_OF_HOURS,108)))- 60 * (SUM(DATEPART(MI,CONVERT(VARCHAR,GTT_NO_OF_HOURS,108)))/60))+''0'') AS [No_of_Hours] '
--SET #si_sql = #si_sql + 'CONVERT(VARCHAR(3),CONVERT(VARCHAR(3),
-- (SUM(DATEPART(HH,CONVERT (VARCHAR,GTT_NO_OF_HOURS,108))) + (SUM(DATEPART(MI,CONVERT (VARCHAR,GTT_NO_OF_HOURS,108)))/60))))+'':''+ CONVERT(VARCHAR(2),CONVERT(VARCHAR(2),
-- SUM(DATEPART(MI,CONVERT (VARCHAR,GTT_NO_OF_HOURS,108)))- 60 * (SUM(DATEPART(MI,CONVERT(VARCHAR,GTT_NO_OF_HOURS,108)))/60))+''0'') - DATEDIFF(day,v_start_date,v_end_date)* 8 AS [twh] from PGATEINTRA.dbo.EMPLOYEE_VACATIONS '
SET #si_sql = #si_sql + ' FROM dbo.gitsTimeTracker '
SET #si_sql = #si_sql + ' inner JOIN dbo.vw_GetUserDetails ON gtt_gu_id = gu_id '
SET #si_sql = #si_sql + ' inner JOIN PGATEINTRA.dbo.EMPLOYEE_VACATIONS ON V_EP_ID = EP_ID '
SET #si_sql = #si_sql + ' WHERE GTT_WORK_DT BETWEEN ''' + #pi_rptFromDate + ''' AND ''' + #pi_rptToDate + ''' '
if isnull(#pi_empId, 0) > 0
SET #si_sql = #si_sql + ' AND gtt_gu_id = ' + CONVERT(varchar(3), #pi_empId)
SET #si_sql = #si_sql + ' GROUP BY [EP_FIRST_NAME], [EP_LAST_NAME] '
print #si_sql
exec(#si_sql)
--Record update process ends here
IF (##ERROR = 0)
return ##ERROR
ELSE
return 1
END
and I got the output from the above procedure is
Employee_Name No_of_hours
-------------------------------------------
Aditya Sastry A 96:00
Suresh A 18:00
Prakash Ajjarapu 12:40
and I wrote one select statement
SELECT DATEDIFF(day,v_start_date,v_end_date)* 8 AS twh from PGATEINTRA.dbo.EMPLOYEE_VACATIONS
and I am getting the output
twh
----
56
8
0
8
8
8
0
16
0
16
0
0
8
8
24
0
88
8
0
56
0
0
0
16
0
8
0
0
0
48
0
8
0
0
24
the thing is i need to substract No_of_hours from twh and that has to be done in the above procedure and that has to be shown in column as twh
how to do it
Your code is rather unclear and difficult to follow, but a general quick and dirty approach when you need to combine the results of two 'complex' queries is to INSERT them into temp tables and then join the temp tables. This assumes of course that you include some suitable values to join the tables on, in this case it looks like it would be an employee ID of some kind.
In other words, you should aim to be able to write something like this:
select
wh.employee_name,
wh.working_hours,
h.holiday_hours,
wh.working_hours - h.holiday_hours as 'total_hours'
from
#working_hours wh
join #holidays h
on wh.employee_id = h.employee_id
I don't think anyone can write the queries for you, because it requires a lot of knowledge about the tables and data, so this is just a general suggestion of one approach that you can take.
When I attempt to cast my FLOATS into CHARS in this procedure, I get null values in the database. Location is a Geospatial field. What am I doing wrong?
CREATE DEFINER=`me`#`%` PROCEDURE `UpdateLocationByObjectId`(IN objectId INT,
IN latitude FLOAT,
IN longitude FLOAT)
BEGIN
UPDATE Positions P
JOIN Objects O ON P.Id = O.PositionId
SET P.Location = GeomFromText('Point(' + CAST(latitude AS CHAR(10)) + ' ' + CAST(longitude AS CHAR(10)) +')')
WHERE O.ObjectId = objectId;
END
If I use this as a test, it works fine.
CREATE DEFINER=`me`#`%` PROCEDURE `UpdateLocationByObjectId`(IN objectId INT,
IN latitude FLOAT,
IN longitude FLOAT)
BEGIN
UPDATE Positions P
JOIN Objects O ON P.Id = O.PositionId
SET P.Location = GeomFromText('Point(10 10')')
WHERE O.ObjectId = objectId;
END
Change this line
SET P.Location = GeomFromText('Point(' + CAST(latitude AS CHAR(10)) + ' '
+ CAST(longitude AS CHAR(10)) +')')
To
SET P.Location = GeomFromText(concat('Point(' , CAST(latitude AS CHAR(10)) , ' '
, CAST(longitude AS CHAR(10)) ,')'))
The + operator is adding your text values ('10' + '10') = 20
So the center part evaluates to 'Point(' + 20 + ')', adding text that cannot be read as number + numbers evaluates to NULL.
Only the concat function can concatenate strings.
In fact this code will work just as well:
SET P.Location = GeomFromText(concat('Point(', latitude, ' ', longitude,')'))