Error in MDW script from SQL tracer - sql

SQL Server MDW comes with built-in reports and I was curious about the underlying code behind the report to customize the reports. I used sql tracer to see what happens and this was the output containing errors. Was wondering if anyone could see what was wrong?
I get the following error:
Msg 4145, Level 15, State 1, Line 26 An expression of non-boolean type
specified in a context where a condition is expected, near ';'.
DECLARE #ServerName varchar(max)
DECLARE #SelectedDatabaseName varchar(max)
DECLARE #snapshot_id int
SELECT TOP 1 #snapshot_id = snapshot_id FROM (
SELECT DISTINCT TOP 100 d.snapshot_id
FROM snapshots.disk_usage d, core.snapshots ss
WHERE ss.instance_name = #ServerName
AND ss.snapshot_id = d.snapshot_id
ORDER BY d.snapshot_id DESC
) AS q
ORDER BY snapshot_id ASC
SELECT
database_name,
CONVERT (datetime, SWITCHOFFSET (CAST (d.collection_time AS datetimeoffset), '+00:00')) AS collection_time,
d.snapshot_id,
((convert(dec (15,2),d.dbsize) + convert(dec(15,2),d.logsize)) * 8192 / 1048576.0) AS 'database_size_mb',
'reserved_mb' = (d.reservedpages * 8192 / 1048576.0),
'data_mb' = convert(dec(15,2),d.pages) * 8192 / 1048576.0,
'index_mb'= (d.usedpages - d.pages) * 8192 / 1048576.0,
'unused_mb' = ((convert(dec (15,2),d.reservedpages) - convert(dec(15,2),d.usedpages)) * 8192 / 1048576.0),
'unallocated_space_mb' = (
case
when d.dbsize >= d.reservedpages
then (convert (dec (15,2),d.dbsize) - convert (dec (15,2),d.reservedpages)) * 8192 / 1048576.0
else 0
end)
FROM snapshots.disk_usage d, core.snapshots ss
WHERE database_name =#SelectedDatabaseName
AND d.snapshot_id >= #snapshot_id
AND ss.instance_name = #ServerName
AND d.snapshot_id = ss.snapshot_id
ORDER BY collection_time asc

Related

The log function requires 1 argument(s) at SQL server

I am trying to run this script on SQL Server:
CREATE FUNCTION [dbo].[IPAddressToCidr](#IP AS VARCHAR(15))
RETURNS INT
AS
BEGIN
DECLARE #result INT;
DECLARE #ipInt BIGINT;
SET #ipInt = CONVERT(BIGINT, PARSENAME(#IP, 1)) + CONVERT(BIGINT, PARSENAME(#IP, 2)) * 256 + CONVERT(BIGINT, PARSENAME(#IP, 3)) * 65536 + CONVERT(BIGINT, PARSENAME(#IP, 4)) * 16777216;
SET #result = CAST(( 32 - LOG(4294967296 - #ipInt, 2)) AS INT);
RETURN #result;
END;
The result error is:
Msg 174, Level 15, State 1, Procedure IPAddressToCidr, Line 11
The log function requires 1 argument(s).
I am trying...
SELECT LOG(4294967296,2) /*this has problem*/
SELECT LOG(4294967296) /*this one works but with different results */
Any help with the Log() function with two parameters?
SQL Server 2012+ supports LOG(expr, [base])
With lower version you can use simple Math to get the result:
SELECT LOG(1024)/LOG(2) -- 10, 2 ^ 10 = 1024
SELECT LOG(1000)/LOG(10) -- 3, 10 ^ 3 = 1000
LiveDemo
Change of base formula:
LOG(#arg,base) = LOG(#arg) / LOG(base)

Invalid object name with #tem_table

I am trying to execute a query to get highCpuUtilization queries alert. It is displaying results, if I am executing the query. When I want to send the results to my mail using dbmail, it is throwing error.
(3 row(s) affected)
(1 row(s) affected)
(1 row(s) affected)
Msg 22050, Level 16, State 1, Line 0 Error formatting query, probably
invalid parameters Msg 14661, Level 16, State 1, Procedure
sp_send_dbmail, Line 517 Query execution failed: Msg 208, Level 16,
State 1, Server FSQADBTRVS\FSQADBTR, Line 1 Invalid object name
'#PossibleCPUUtilizationQueries'.
Here is the Query, That I am trying to Run
DECLARE #ts_now bigint
DECLARE #SQLVersion decimal (4,2) -- 9.00, 10.00
DECLARE #AvgCPUUtilization DECIMAL(10,2)
SELECT #SQLVersion = LEFT(CAST(SERVERPROPERTY('PRODUCTVERSION') AS VARCHAR), 4) -- find the SQL Server Version
-- sys.dm_os_sys_info works differently in SQL Server 2005 vs SQL Server 2008+
-- comment out SQL Server 2005 if SQL Server 2008+
-- SQL Server 2005
--IF #SQLVersion = 9.00
--BEGIN
-- SELECT #ts_now = cpu_ticks / CONVERT(float, cpu_ticks_in_ms) FROM sys.dm_os_sys_info
--END
-- SQL Server 2008+
IF #SQLVersion >= 10.00
BEGIN
SELECT #ts_now = cpu_ticks/(cpu_ticks/ms_ticks) FROM sys.dm_os_sys_info
END
-- load the CPU utilization in the past 3 minutes into the temp table, you can load them into a permanent table
SELECT TOP(3) SQLProcessUtilization AS [SQLServerProcessCPUUtilization]
,SystemIdle AS [SystemIdleProcess]
,100 - SystemIdle - SQLProcessUtilization AS [OtherProcessCPU Utilization]
,DATEADD(ms, -1 * (#ts_now - [timestamp]), GETDATE()) AS [EventTime]
INTO #CPUUtilization
FROM (
SELECT record.value('(./Record/#id)[1]', 'int') AS record_id,
record.value('(./Record/SchedulerMonitorEvent/SystemHealth/SystemIdle)[1]', 'int')
AS [SystemIdle],
record.value('(./Record/SchedulerMonitorEvent/SystemHealth/ProcessUtilization)[1]',
'int')
AS [SQLProcessUtilization], [timestamp]
FROM (
SELECT [timestamp], CONVERT(xml, record) AS [record]
FROM sys.dm_os_ring_buffers
WHERE ring_buffer_type = N'RING_BUFFER_SCHEDULER_MONITOR'
AND record LIKE '%<SystemHealth>%') AS x
) AS y
ORDER BY record_id DESC
-- check if the average CPU utilization was over 90% in the past 2 minutes
SELECT #AvgCPUUtilization = AVG([SQLServerProcessCPUUtilization] + [OtherProcessCPU Utilization])
FROM #CPUUtilization
WHERE EventTime > DATEADD(MM, -2, GETDATE())
IF #AvgCPUUtilization >= 0
BEGIN
SELECT TOP(10)
CONVERT(VARCHAR(25),#AvgCPUUtilization) +'%' AS [AvgCPUUtilization]
, GETDATE() [Date and Time]
, r.cpu_time
, r.total_elapsed_time
, s.session_id
, s.login_name
, s.host_name
, DB_NAME(r.database_id) AS DatabaseName
, SUBSTRING (t.text,(r.statement_start_offset/2) + 1,
((CASE WHEN r.statement_end_offset = -1
THEN LEN(CONVERT(NVARCHAR(MAX), t.text)) * 2
ELSE r.statement_end_offset
END - r.statement_start_offset)/2) + 1) AS [IndividualQuery]
, SUBSTRING(text, 1, 200) AS [ParentQuery]
, r.status
, r.start_time
, r.wait_type
, s.program_name
INTO #PossibleCPUUtilizationQueries
FROM sys.dm_exec_sessions s
INNER JOIN sys.dm_exec_connections c ON s.session_id = c.session_id
INNER JOIN sys.dm_exec_requests r ON c.connection_id = r.connection_id
CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) t
WHERE s.session_id > 50
AND r.session_id != ##spid
order by r.cpu_time desc
-- query the temp table, you can also send an email report
SELECT * FROM #PossibleCPUUtilizationQueries
END
EXEC msdb.dbo.sp_send_dbmail
#profile_name = 'Databasemail',
#recipients = 'con-balususr#mail.com',
#query = 'SELECT * FROM #PossibleCPUUtilizationQueries',
#subject = 'Work Order Count',
#attach_query_result_as_file = 1 ;
-- drop the temp tables
IF OBJECT_ID('TEMPDB..#CPUUtilization') IS NOT NULL
drop table #CPUUtilization
IF OBJECT_ID('TEMPDB..#PossibleCPUUtilizationQueries') IS NOT NULL
drop table #PossibleCPUUtilizationQueries
EXEC msdb.dbo.sp_send_dbmail will run in a different context and has no permissions to your declared temporary table.
Use a global temporary table instead (##PossibleCPUUtilizationQueries).
As Aaron quite rightly pointed out you could also just use a permanent table to store your data rather than use temporary tables.
See here for more information regarding local and global temporary tables
There are two types of temporary tables: local and global. Local
temporary tables are visible only to their creators during the same
connection to an instance of SQL Server as when the tables were first
created or referenced. Local temporary tables are deleted after the
user disconnects from the instance of SQL Server. Global temporary
tables are visible to any user and any connection after they are
created, and are deleted when all users that are referencing the table
disconnect from the instance of SQL Server.

Recursive UNION ALL to parse string taking very long

I am trying to speed up this recursive UNION ALL as shown below, but I cannot think how to do it. Maybe a while loop but I am not sure. The movement data is stored as one long string of encoded movement data and the script recursively calls the select statement to parse/extract this data and then it is all casted.
I would really like to understand more about speeding up recursive union all's or finding another way. I don't believe indexing is a problem so this is not really a possible solution.
"RouteData" is the long string that is parsed by fixed length intervals.
Here is a sample of the encoded data:
ScenarioPID : 3
LegID :1
RoutePart : 0x0000000000000000000100000000000000000000000000
RouteData : 0x40323AAAAAAAAAAB00013FA6FFD663CCA3310000001F00403 ... (goes on)
cnt : 37
sequence : 1
StartTime : 8828
The final output data looks like this for one track.
ScenarioPID LegID sequence TrackID Offset TimeOffset Length StartTime
3 1 1 1 0 0 6300 8828
3 1 2 1 0.0449 31 6300 8828
3 1 3 1 0.8942 325 6300 8828
3 1 4 1 0.9736 356 6300 8828
3 1 5 1 1 369 6300 8828
USE nss_demo;
DECLARE #scenario1 INT;
DECLARE #DAY_START INT;
DECLARE #DAY_END INT;
DECLARE #TRAIN_TYPE VARCHAR(50);
DECLARE #TRACK_TYPE VARCHAR(50);
SET #scenario1 = 3;
SET #DAY_START = 0;
SET #DAY_END = 7;
SET #TRAIN_TYPE = 'Empty Train';
SET #TRACK_TYPE = 'East Track';
DECLARE #KM_START INT;
DECLARE #KM_END INT;
SET #KM_START = 0;
SET #KM_END = 200;
WITH movement
AS (SELECT m.scenariopid,
m.legid,
Substring(routedata, 1, 23) AS RoutePart,
Substring(routedata, 24, Len(routedata) - 23) AS RouteData,
Len(routedata) / 23 - 1 AS cnt,
1 AS sequence,
m.starttime
FROM output.movement m
WHERE scenariopid = #scenario1
AND m.starttime BETWEEN ( #DAY_START * 86400 ) AND
( #DAY_END * 86400 )
UNION ALL
SELECT scenariopid,
legid,
Substring(m1.routedata, 1, 23) AS RoutePart
,
Substring(m1.routedata, 24,
Len(m1.routedata) - 23) AS RouteData,
Len(m1.routedata) / 23 - 1 AS cnt,
sequence + 1 AS sequence,
m1.starttime
FROM movement m1
WHERE m1.cnt > 0),
casttable
AS (SELECT tt.scenariopid,
tt.legid,
tt.sequence,
tt.trackid,
tt.offset,
tt.timeoffset,
tr.[length],
tt.starttime
FROM (SELECT scenariopid,
legid,
sequence,
Cast(trackidbin AS SMALLINT) AS TrackID,
Sign(Cast(offsetbin AS BIGINT)) *
( 1.0 +
( Cast(offsetbin AS BIGINT) & 0x000FFFFFFFFFFFFF ) *
Power(Cast(2 AS FLOAT), -52) )
*
Power(Cast(2 AS FLOAT), ( Cast(offsetbin AS BIGINT) &
0x7ff0000000000000
) /
0x0010000000000000
- 1023) AS Offset,
Cast(timebin AS INT) AS TimeOffset,
starttime AS StartTime
FROM (SELECT legid,
scenariopid,
sequence,
Substring(routepart, 9, 2) AS TrackIDBin,
Substring(routepart, 11, 8) AS OffsetBin,
Substring(routepart, 19, 4) AS TimeBin,
starttime
FROM movement) t) tt
INNER JOIN input.track tr
ON tr.trackid = tt.trackid
AND tr.scenariopid = tt.scenariopid)
SELECT *
FROM casttable
ORDER BY legid,
sequence
OPTION (maxrecursion 20000)
Use a Numbers Table (zero-based assumed below) to create CTE movement like this:
WITH movement
AS (SELECT m.scenariopid,
m.legid,
Substring(routedata, n.N*23 + 1, 23) AS RoutePart,
n.N AS cnt,
-- 1 AS sequence, -- use a row_number function here instead, as per your vendor.
m.starttime
FROM output.movement m
JOIN Numbers n
on n < Len(routedata) / 23
WHERE scenariopid = #scenario1
AND m.starttime BETWEEN ( #DAY_START * 86400 ) AND
( #DAY_END * 86400 )
),
-- etc.
If you don't have a static Numbers Table, my answer here demonstrates how to create one dynamically in a CTE.

How to use SQL ROW_NUMBER with INNER JOIN?

I have written this query to get data for special keyword:
ALTER procedure [dbo].[GetAllSpecialPaperTags]
#PKeyword nvarchar(200)
as
begin
select
Papers.PID, Papers.PTitle, Papers.PaperSummary
from
PaperKeywords
left join
PaperTags on PaperKeywords.PKeyID = PaperTags.PKeyID
left join
Papers on PaperTags.PID = Papers.PID
where
PaperKeywords.PKeyword = #PKeyword
end
I want use this article for custom paging : Custom Paging using SQL Server Stored Procedure
I wrote this query but I'm getting an error:
create procedure [dbo].[GetAllSpecialPaperTags]
#PageIndex INT = 1
,#PageSize INT = 10
,#RecordCount INT OUTPUT
,#PKeyword nvarchar(200)
as
BEGIN
SET NOCOUNT ON;
SELECT ROW_NUMBER() OVER
(
ORDER BY [Papers.PID] ASC
)AS RowNumber
,Papers.PID , Papers.PTitle , Papers.PaperSummary
INTO #Results
from PaperKeywords
left join PaperTags on PaperKeywords.PKeyID = PaperTags.PKeyID
left join Papers on PaperTags.PID = Papers.PID where PaperKeywords.PKeyword = #PKeyword
SELECT #RecordCount = COUNT(*)
FROM #Results
SELECT * FROM #Results
WHERE RowNumber BETWEEN(#PageIndex -1) * #PageSize + 1 AND(((#PageIndex -1) * #PageSize + 1) + #PageSize) - 1
DROP TABLE #Results
end
Error:
Msg 207, Level 16, State 1, Procedure GetAllSpecialPaperTags, Line 11
Invalid column name 'Papers.PID'.
Why?
This is your order by expression:
ORDER BY [Papers.PID] ASC
It is looking for a column named in its entirety "Papers.PID". It is not looking for the PID column in Papers. Just drop the braces:
ORDER BY Papers.PID ASC

Can you query the maximum database size based on the SQL Server license?

Depending on the licensing and configuration of your SQL Server database, you may have have very different size restrictions. For example:
SQL Server 2012 Express has a limit of 10GB
SQL Server 2008 R2 Express has a limit of 10GB
SQL Server 2008 Express has a limit of 4GB
Is it possible to query the database server to find out what the maximum size is?
I can query to find out the current size:
name DataFileSizeMB LogFileSizeMB
--------- -------------- -------------
master 4.875000 1.750000
tempdb 8.000000 0.500000
model 4.062500 1.000000
msdb 16.687500 4.562500
Harrison 21.937500 18.187500
Lennon 122.750000 425.625000
McCartney 19.937500 49.687500
Starr 19.937500 18.187500
What I'm now after, is a way to find out what the maximum is, based on the licensing not the available HDD space.
Try this one -
SELECT
d.server_name
, d.sversion_name
, d.edition
, max_db_size_in_gb =
CASE WHEN engine_edition = 4
THEN
CASE
WHEN d.sversion_name LIKE '%2012%' THEN 10
WHEN d.sversion_name LIKE '%2008 R2%' THEN 10
WHEN d.sversion_name LIKE '%2008%' THEN 4
WHEN d.sversion_name LIKE '%2005%' THEN 4
END
ELSE -1
END
FROM (
SELECT
sversion_name = SUBSTRING(v.ver, 0, CHARINDEX('-', v.ver) - 1)
, engine_edition = SERVERPROPERTY('EngineEdition')
, edition = SERVERPROPERTY('Edition')
, server_name = SERVERPROPERTY('ServerName')
FROM (SELECT ver = ##VERSION) v
) d
Also, try this query to get extended info about DB -
IF EXISTS(
SELECT 1
FROM tempdb.dbo.sysobjects
WHERE id = OBJECT_ID('tempdb.dbo.#DBObj')
) DROP TABLE #DBObj
CREATE TABLE #DBObj
(
[DB] SYSNAME
, reservedpages INT
, usedpages INT
, pages INT
)
EXEC sys.sp_MSforeachdb '
USE [?]
INSERT INTO #DBObj
(
[DB]
, reservedpages
, usedpages
, pages
)
SELECT
DB_NAME()
, pg.reservedpages
, pg.usedpages
, pg.pages
FROM (
SELECT
reservedpages = SUM(a.total_pages)
, usedpages = SUM(a.used_pages)
, pages = SUM(
CASE
WHEN it.internal_type IN (202, 204, 207, 211, 212, 213, 214, 215, 216, 221, 222) THEN 0
WHEN a.[type] != 1 AND p.index_id < 2 THEN a.used_pages
WHEN p.index_id < 2 THEN a.data_pages ELSE 0
END
)
FROM sys.partitions p
JOIN sys.allocation_units a ON p.[partition_id] = a.container_id
LEFT JOIN sys.internal_tables it ON p.[object_id] = it.[object_id]
) pg'
SELECT
d.name
, total_size_mb = data.row_size_mb + data.log_size_mb
, data.log_size_mb
, data.row_size_mb
, reserved_space_mb = CAST(do.reservedpages * 8. / 1024 AS DECIMAL(10,2))
, data_size_mb = CAST(do.pages * 8. / 1024 AS DECIMAL(10,2))
, index_size_mb = CAST((do.usedpages - do.pages) * 8. / 1024 AS DECIMAL(10,2))
, unused_size_mb = CAST((do.reservedpages - do.usedpages) * 8. / 1024 AS DECIMAL(10,2))
, unallocated_space_mb =
CAST(CASE WHEN data.row_size >= do.reservedpages
THEN (data.row_size - do.reservedpages) * 8. / 1024
ELSE 0
END AS DECIMAL(10,2))
FROM (
SELECT
df2.database_id
, log_size_mb = CAST(df2.log_size * 8. / 1024 AS DECIMAL(10,2))
, row_size_mb = CAST(df2.row_size * 8. / 1024 AS DECIMAL(10,2))
, df2.log_size
, df2.row_size
FROM (
SELECT
df.database_id
, log_size = SUM(CASE WHEN df.type_desc = 'LOG' THEN df.size END)
, row_size = SUM(CASE WHEN df.type_desc = 'ROWS' THEN df.size END)
FROM sys.master_files df
GROUP BY df.database_id
) df2
) data
JOIN sys.databases d ON data.database_id = d.database_id
JOIN #DBObj do ON do.DB = d.name
ORDER BY data.row_size_mb + data.log_size_mb DESC
I linke Devart's ansatz, but how about something a bit more compact:
SELECT max_db_size_in_gb =
CASE WHEN serverproperty('EngineEdition') = 4 THEN
CASE WHEN SERVERPROPERTY('productversion') between '10.50' and '5' THEN 10 ELSE 4 END
ELSE -1
END
(Instead of parsing the output of ##VERSION, checking SERVERPROPERTY('productversion') is surely easier? Also, this is safer when new versions like SQL Server 2014 are released.)
(Edited: Old version was just checking for "< '10.50'", which of course is wrong since e.g. '9.00' (SQL Server 2005) is lexicographically bigger!)
I'm not sure how to do it at a "give me the max size of the database"-level, but you could query sys.database_files and piece it together from the files which make up the database.
I think the relevant column will be max_size, which is the max file size in 8KB pages.
PS. sys.database_files is a per-database view, if you wanted to view it across your entire SQL Server instance then sys.master_files may be better....
All sizes reported are in MB
Note - there are better ways to check whether a file is a log or data file; checking for ".ldf" suffix here works for 99% of installations.
if object_id('tempdb..#sizes') is not null
drop table #sizes;
GO
create table #sizes (dbname sysname, cursize int, maxsize int, isunlimited int, curlogsize int, maxlogsize int, islogunlimited int);
exec sp_msforeachdb '
insert #sizes
select ''?'',
sum(case when filename like ''%.ldf'' then 0 else size end),
sum(case when filename like ''%.ldf'' then 0 else maxsize end),
min(case when filename like ''%.ldf'' then 0 else maxsize end),
sum(case when filename like ''%.ldf'' then size else 0 end),
sum(case when filename like ''%.ldf'' then maxsize else 0 end),
min(case when filename like ''%.ldf'' then maxsize else 0 end)
from [?].sys.sysfiles';
select dbname, cursize / 128.0,
case when isunlimited = -1 then 'unlimited' else str(maxsize/128.0) end, curlogsize/128.0,
case when islogunlimited = -1 then 'unlimited' else str(maxlogsize/128.0) end
from #sizes
order by dbname;