My stored procedure text search is buggy - tsql

I'm stuck - I have this nice little text searcher I've put together.
I realised I needed to count lnies in individual blocks of text that the stored procedure is stored in, so I think I've figured a way to do that.
But it's not getting every instance of a search term in a stored procedure - and I think it's the same reason... the search term is split across a text boundary.
I've looked at how to change my query - and I'm coming up blank. The skills involved to change it are beyond me!
--Text searcher.
DECLARE #searchString VARCHAR(255),
#doesNotContain VARCHAR(255),
#previewLength INTEGER,
#findStoredProcedures VARCHAR(3),
#findTableFunction VARCHAR(3),
#findScalerFunction VARCHAR(3),
#findTrigger VARCHAR(3),
#findView VARCHAR(3),
#findUserTable VARCHAR(3),
#onlyInName VARCHAR(3)
--------------------------------------------------------
-- Search criteria:
SET #searchString = 'My search Term'
SET #findStoredProcedures = 'yes'
SET #findTableFunction = 'yes'
SET #findScalerFunction = 'yes'
SET #findUserTable = 'yes'
SET #findTrigger = 'yes'
SET #findView = 'yes'
SET #doesNotContain = ''
SET #previewLength = 30
--------------------------------------------------------
SELECT DISTINCT
ISNULL(
(SELECT REPLACE(CONVERT(VARCHAR(20), (CAST(SUM(LEN(SC2.text)) AS MONEY)), 1), '.00', '')
FROM syscomments SC2 WHERE SC2.id = SO.id GROUP BY SC2.id)
, '')
AS [Object length]
,
SO.name AS [Object name]
,
CASE
WHEN SO.xtype = 'P' THEN 'Stored Procedure'
WHEN SO.xtype = 'TF' THEN 'Table Function'
WHEN SO.xtype = 'FN' THEN 'Scaler Function'
WHEN SO.xtype = 'U' THEN 'User Table'
WHEN SO.xtype = 'TR' THEN 'Trigger'
WHEN SO.xtype = 'V' THEN 'View'
END
+ ISNULL((SELECT ' - ' + name FROM sysobjects WHERE id = SO.parent_obj), '')
AS [Object type]
,
ISNULL(SUBSTRING(SC.text, CHARINDEX(#searchString, SC.text) - #previewLength, #previewLength) +
SUBSTRING(SC.text, CHARINDEX(#searchString, SC.text), #previewLength + LEN(#searchString))
, '') AS [Preview of code]
,
(SELECT
COALESCE(
SUM(LEN(SC3.text) - LEN(REPLACE(SC3.text, CHAR(13), '')) + 1) + 4
+
(
SELECT
(LEN(LEFT(SC4.text, CHARINDEX(#searchString, SC4.text))) -
LEN(REPLACE(LEFT(SC4.text, CHARINDEX(#searchString, SC4.text)), CHAR(13), '')))
FROM syscomments SC4
WHERE
SC4.id = SO.id
AND SC4.colid = SC.colid
)
,
SUM(LEN(SC3.text) - LEN(REPLACE(SC3.text, CHAR(13), '')) + 1) + 4
,
(
SELECT
(LEN(LEFT(SC4.text, CHARINDEX(#searchString, SC4.text))) -
LEN(REPLACE(LEFT(SC4.text, CHARINDEX(#searchString, SC4.text)), CHAR(13), '')) + 1)
FROM syscomments SC4
WHERE
SC4.id = SO.id
AND SC4.colid = SC.colid
)
)
FROM syscomments SC3
WHERE
SC3.id = SO.id
AND SC3.colid < SC.colid
)
AS [Line number]
FROM sysobjects SO
LEFT JOIN syscomments SC
ON SO.id = SC.id
WHERE
(
(SO.type = 'P' AND #findStoredProcedures = 'yes')
OR
(SO.type = 'TF' AND #findTableFunction = 'yes')
OR
(SO.type = 'FN' AND #findScalerFunction = 'yes')
OR
(SO.type = 'TR' AND #findTrigger = 'yes')
OR
(SO.type = 'U' AND #findUserTable = 'yes')
OR
(SO.type = 'V' AND #findView = 'yes')
)
AND SO.category = 0
AND
(
(CHARINDEX(#searchString, SC.text) > 0
AND CHARINDEX(#doesNotContain, SC.text) = 0)
OR
(SO.type = 'U'
AND CHARINDEX(#searchString, SO.name) > 0
AND CHARINDEX(#doesNotContain, SO.name) = 0)
)
ORDER BY
[Object type], [Object name], [Line number]

Your where clause seems to have an issue, this bit here
(
(CHARINDEX(#searchString, SC.text) > 0
AND CHARINDEX(#doesNotContain, SC.text) = 0)
--OR
--(SO.type = 'U'
--AND CHARINDEX(#searchString, SO.name) > 0
--AND CHARINDEX(#doesNotContain, SO.name) = 0)

Related

Power BI - SQL: Incorrect syntax near the keyword 'DECLARE'. Incorrect syntax near ')'

New to SQL and was given the query below to use in Power BI. It pulls the data table correctly on preview but fails when applying the change into Power BI Desktop. I don't know how to fix the syntax.
I get this error:
Power BI - SQL: Incorrect syntax near the keyword 'DECLARE'. Incorrect syntax near ')'.
Here is the query:
DECLARE #CLIENT AS NVARCHAR(32)
DECLARE #FULLVERSION AS NVARCHAR(10)
DECLARE #DATERUN AS DATETIME
DECLARE #ANON AS INT --1 to set anonymised mode on, 0 to set it to off
DECLARE #FROMDATE AS DATE --(FORMAT = YYYYMMDD) --UPDATE
DECLARE #TODATE AS DATE --(FORMAT = YYYYMMDD) --UPDATE
SET #CLIENT = 'HOGANS'
--SET #FULLVERSION = (SELECT MAX(BH_Version) FROM BH_Version)
SET #DATERUN = ( Getdate() )
SET #ANON = 0
SET #FROMDATE = '20211101' --(FORMAT = YYYYMMDD) --UPDATE
SET #TODATE = '20211231' --(FORMAT = YYYYMMDD) --UPDATE
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET nocount ON;
-- Insert statements for procedure here
SELECT #Client AS
ClientName,
#DATERUN AS DateRun,
#FROMDATE AS
QueryVariable_FromDate,
#TODATE AS
QueryVariable_ToDate,
-- #FULLVERSION as BHVersionWhenRun,
T.bh_taskguid,
RIGHT(Datepart(yy, T.bh_creationdate), 2)
+ RIGHT('00'+ CONVERT(NVARCHAR(2), Datepart(mm, T.bh_creationdate)), 2)
+ '-' + CONVERT(NVARCHAR, T.bh_referenceid) AS TaskID,
Auth.bh_userguid AS
AuthorGUID,
CASE
WHEN #ANON = 0 THEN Auth.bh_username
WHEN #ANON = 1 THEN NULL
END AS
AuthorName,
AuthDept.bh_departmentname AS
AuthorDepartmentName,
(SELECT TOP 1 AD.bh_departmentname
FROM bh_historic_report_departments AS AD
WHERE AuthDept.bh_parentguid = AD.bh_departmentguid) AS
AuthorDepartmentParent,
--THIS CHECKS THE HISTORIC DEPT STRUCTURE TO GET THE NAME OF THE PARENT DEPARTMENT OF THE AUTHOR
Sec.bh_userguid AS
CompletedByGUID,
CASE
WHEN #ANON = 0 THEN Sec.bh_username
WHEN #ANON = 1 THEN NULL
END AS
CompletedByName,
SecDept.bh_departmentname AS
CompletedByDepartmentName,
(SELECT TOP 1 SD.bh_departmentname
FROM bh_historic_report_departments AS SD
WHERE SecDept.bh_parentguid = SD.bh_departmentguid) AS
SecDepartmentParent,
--THIS CHECKS THE HISTORIC DEPT STRUCTURE TO GET THE NAME OF THE PARENT DEPARTMENT OF THE SECRETARY
CASE
WHEN #ANON = 0 THEN (SELECT TOP 1 HU.bh_username
--BH_UserGuid and remove the join for GUID only
FROM bh_historic_report_taskaudit HTA
INNER JOIN bh_historic_report_users AS HU
ON ( HU.bh_userguid =
HTA.bh_userguid )
WHERE ( HTA.bh_taskguid = T.bh_taskguid )
ORDER BY bh_auditid ASC)
WHEN #ANON = 1 THEN NULL
END AS
'Submitted By (Name)',
(SELECT TOP 1 bh_userguid
FROM bh_historic_report_taskaudit
WHERE ( bh_taskguid = T.bh_taskguid )
ORDER BY bh_auditid ASC) AS
'Submitted By (GUID)',
(SELECT bh_username
FROM bh_locks
WHERE bh_objectguid = t.bh_taskguid) AS
'Locked By',
CASE
WHEN (SELECT bh_username
FROM bh_locks
WHERE bh_objectguid = t.bh_taskguid) IS NULL THEN 'Pending'
WHEN Sec.bh_userguid IS NULL THEN 'In Progress'
ELSE 'Complete'
END AS
'TaskStatus',
CASE
WHEN (SELECT TOP 1 bh_userguid
FROM bh_historic_report_taskaudit
WHERE ( bh_taskguid = T.bh_taskguid )
ORDER BY bh_auditid ASC) = Auth.bh_userguid THEN 'Author'
ELSE 'On Behalf'
END AS
'Logged by',
WF.bh_workflowname AS
WorkflowName,
CASE
WHEN DT.bh_workflowname IS NOT NULL THEN DT.bh_workflowname
ELSE 'Not Configured'
END AS
'Work Type Should Go To',
CASE
WHEN ( DT.bh_workflowguid = T.bh_workflowguid ) THEN 'Correct Workflow'
--If no default workflow is specified then we assume this is sent to the correct workflow.
WHEN ( DT.bh_workflowguid IS NULL ) THEN 'No Default Workflow'
ELSE 'Incorrect Workflow'
END AS
'Sent To Correct Workflow',
-- ONLY POSSIBLE ON V5 AND ABOVE
CASE
WHEN ( T.bh_source = '15' ) -- Sent from Forms Desktop Assistant
--OR the below which includes iOS (10, 11), Android (12), Now Mail (4) and Hub (18)
OR ( T.bh_lengthintenths = '0'
AND T.bh_source IN ( '18', '10', '11', '12', '4' ) )
--AND T.BH_DocumentType NOT IN (SELECT BH_DocumentTypeName FROM BH_DocumentTypes)) -- assuming that if WT no longer exists and is zero length and is sent from Hub (i.e. not from Mobile, Classic etc which can't send Now tasks) then NOW
THEN 'TASK'
ELSE 'VOICE'
END AS
'Task Type (TASK or VOICE)',
--FOR V4, MANUALLY APPLYING ALL VOICE AS TASK TYPE
-- 'VOICE' as 'Task Type (NOW or VOICE)',
CASE
WHEN #ANON = 0 THEN T.bh_title
WHEN #ANON = 1 THEN NULL
ELSE NULL
END AS
'BH_Title',
T.bh_documenttype AS WorkType
,
T.bh_creationdate,
T.bh_senddate,
T.bh_sentpriority,
CASE
WHEN TA.priorities > 1 THEN 'YES'
ELSE 'NO'
END AS
'PriorityChanged',
T.bh_completiondate,
CASE
WHEN ( T.bh_requiredby IS NOT NULL )
AND ( T.bh_completiondate <= T.bh_requiredby ) THEN 'On Time'
WHEN ( T.bh_requiredby IS NOT NULL )
AND ( T.bh_completiondate > T.bh_requiredby ) THEN 'Overdue'
WHEN T.bh_requiredby IS NULL THEN 'No Deadline Set'
END AS OnTime,
T.bh_priorityname,
T.bh_requiredby,
CASE
WHEN TA.requiredby > 1 THEN 'YES'
ELSE 'NO'
END AS
'RequiredByChanged',
T.bh_sourcetimezone AS
TimeZoneOffset,
T.bh_turnaroundtime AS
TurnaroundTimeInSec,
--NOTE: this is the difference in seconds between the send date and the completion date
-- (
-- RIGHT('000' + CONVERT(VARCHAR, T.BH_TurnaroundTime / 3600 / 24),3) + ':'
-- + RIGHT('00' + CONVERT(VARCHAR, T.BH_TurnaroundTime / 3600 % 24),2) + ':'
-- + RIGHT('00' + CONVERT(VARCHAR, T.BH_TurnaroundTime / 60 % 60),2) + ':'
-- + RIGHT('00' + CONVERT(VARCHAR,T.BH_TurnaroundTime % 60),2)
-- ) AS TurnaroundTimeDays,
T.bh_numreassignments,
CASE
WHEN ( T.bh_source = '0' ) THEN 'Classic Client'
WHEN ( T.bh_source = '4' ) THEN 'Now Mail'
WHEN ( T.bh_source = '5' ) THEN 'Web Client'
WHEN ( T.bh_source = '6' ) THEN 'Windows Mobile'
WHEN ( T.bh_source = '7' ) THEN 'BlackBerry'
WHEN ( T.bh_source = '8' ) THEN 'Hosted Services Client'
WHEN ( T.bh_source = '9' ) THEN 'Work Manager'
WHEN ( T.bh_source = '10' ) THEN 'BigHand Go'
WHEN ( T.bh_source = '11' ) THEN 'BigHand Mobile iPhone'
WHEN ( T.bh_source = '12' ) THEN 'Android'
WHEN ( T.bh_source = '13' ) THEN 'BlackBerry 10'
WHEN ( T.bh_source = '14' ) THEN 'Windows Phone'
WHEN ( T.bh_source = '15' ) THEN 'BigHand Now'
WHEN ( T.bh_source = '16' ) THEN 'BigHand Go For Windows'
WHEN ( T.bh_source = '17' ) THEN 'BigHand Go For Windows Phone'
WHEN ( T.bh_source = '18' ) THEN 'Hub'
END AS 'Source'
,
T.bh_sourcetimezone,
--(
-- RIGHT('00' + CONVERT(VARCHAR, (T.BH_LengthInTenths/10) / 3600 % 24),2) + ':'
-- + RIGHT('00' + CONVERT(VARCHAR, (T.BH_LengthInTenths/10) / 60 % 60),2) + ':'
-- + RIGHT('00' + CONVERT(VARCHAR,(T.BH_LengthInTenths/10) % 60),2)
-- ) AS LengthInHours,
( T.bh_lengthintenths / 10 ) AS
LengthInSeconds,
( T.bh_lengthintenths / 10 ) / 60 AS
LengthInMins,
(SELECT Sum(Datediff(second, bh_startdate, bh_enddate))
FROM bh_historic_report_taskaudit
WHERE ( bh_taskguid = T.bh_taskguid )) AS
'Total Processing Time (Sec)',
--(
-- RIGHT('00' + CONVERT(VARCHAR, (SELECT sum(datediff(SECOND,BH_StartDate, BH_EndDate))
-- FROM BH_HISTORIC_REPORT_TASKAUDIT
-- WHERE (BH_TaskGuid = T.BH_TaskGuid) AND BH_StartDate >= T.BH_SendDate) / 3600 % 24),2) + ':'
--+ RIGHT('00' + CONVERT(VARCHAR, (SELECT sum(datediff(SECOND,BH_StartDate, BH_EndDate))
-- FROM BH_HISTORIC_REPORT_TASKAUDIT
-- WHERE (BH_TaskGuid = T.BH_TaskGuid) AND BH_StartDate >= T.BH_SendDate) / 60 % 60),2) + ':'
--+ RIGHT('00' + CONVERT(VARCHAR,(SELECT sum(datediff(SECOND,BH_StartDate, BH_EndDate))
-- FROM BH_HISTORIC_REPORT_TASKAUDIT
-- WHERE (BH_TaskGuid = T.BH_TaskGuid) AND BH_StartDate >= T.BH_SendDate) % 60),2)
--) AS TotalProcessingHours,
( Isnull((SELECT Sum(Datediff(second, bh_startdate, bh_enddate))
FROM bh_historic_report_taskaudit
WHERE ( bh_taskguid = T.bh_taskguid )
AND ( bh_userguid = T.bh_authorguid )), 0) ) AS
'Author Processing Time (Sec)',
--(ISNULL((
-- RIGHT('00' + CONVERT(VARCHAR, (SELECT sum(datediff(SECOND,BH_StartDate, BH_EndDate))
-- FROM BH_HISTORIC_REPORT_TASKAUDIT
-- WHERE (BH_TaskGuid = T.BH_TaskGuid) AND (BH_UserGuid = T.BH_AuthorGuid) AND (BH_StartDate >= T.BH_SendDate)) / 3600 % 24),2) + ':'
-- + RIGHT('00' + CONVERT(VARCHAR, (SELECT sum(datediff(SECOND,BH_StartDate, BH_EndDate))
-- FROM BH_HISTORIC_REPORT_TASKAUDIT
-- WHERE (BH_TaskGuid = T.BH_TaskGuid) AND (BH_UserGuid = T.BH_AuthorGuid) AND (BH_StartDate >= T.BH_SendDate)) / 60 % 60),2) + ':'
-- + RIGHT('00' + CONVERT(VARCHAR,(SELECT sum(datediff(SECOND,BH_StartDate, BH_EndDate))
-- FROM BH_HISTORIC_REPORT_TASKAUDIT
-- WHERE (BH_TaskGuid = T.BH_TaskGuid) AND (BH_UserGuid = T.BH_AuthorGuid) AND (BH_StartDate >= T.BH_SendDate)) % 60),2)), '00:00:00')
-- ) AS AuthorProcessingHours,
( Isnull((SELECT Sum(Datediff(second, bh_startdate, bh_enddate))
FROM bh_historic_report_taskaudit
WHERE ( bh_taskguid = T.bh_taskguid )
AND ( bh_userguid <> T.bh_authorguid )
AND ( bh_startdate >= T.bh_senddate )), 0) ) AS
'Non-Author Processing Time (Sec)',
--(ISNULL((
-- RIGHT('00' + CONVERT(VARCHAR, (SELECT sum(datediff(SECOND,BH_StartDate, BH_EndDate))
-- FROM BH_HISTORIC_REPORT_TASKAUDIT
-- WHERE (BH_TaskGuid = T.BH_TaskGuid) AND (BH_UserGuid <> T.BH_AuthorGuid) AND (BH_StartDate >= T.BH_SendDate)) / 3600 % 24),2) + ':'
--+ RIGHT('00' + CONVERT(VARCHAR, (SELECT sum(datediff(SECOND,BH_StartDate, BH_EndDate))
-- FROM BH_HISTORIC_REPORT_TASKAUDIT
-- WHERE (BH_TaskGuid = T.BH_TaskGuid) AND (BH_UserGuid <> T.BH_AuthorGuid) AND (BH_StartDate >= T.BH_SendDate)) / 60 % 60),2) + ':'
--+ RIGHT('00' + CONVERT(VARCHAR,(SELECT sum(datediff(SECOND,BH_StartDate, BH_EndDate))
-- FROM BH_HISTORIC_REPORT_TASKAUDIT
-- WHERE (BH_TaskGuid = T.BH_TaskGuid) AND (BH_UserGuid <> T.BH_AuthorGuid) AND (BH_StartDate >= T.BH_SendDate)) % 60),2)), '00:00:00')
--) AS NonAuthorProcessingHours,
(SELECT Sum(bh_playtime)
FROM bh_historic_report_taskaudit
WHERE ( bh_taskguid = T.bh_taskguid )
AND ( bh_startdate >= T.bh_senddate )) AS
'TotalPlay Time',
--(
-- RIGHT('00' + CONVERT(VARCHAR, (SELECT sum(BH_PlayTime)
-- FROM BH_HISTORIC_REPORT_TASKAUDIT
-- WHERE (BH_TaskGuid = T.BH_TaskGuid) AND (BH_StartDate >= T.BH_SendDate)) / 3600 % 24),2) + ':'
--+ RIGHT('00' + CONVERT(VARCHAR, (SELECT sum(BH_PlayTime)
-- FROM BH_HISTORIC_REPORT_TASKAUDIT
-- WHERE (BH_TaskGuid = T.BH_TaskGuid) AND (BH_StartDate >= T.BH_SendDate)) / 60 % 60),2) + ':'
--+ RIGHT('00' + CONVERT(VARCHAR,(SELECT sum(BH_PlayTime)
-- FROM BH_HISTORIC_REPORT_TASKAUDIT
-- WHERE (BH_TaskGuid = T.BH_TaskGuid) AND (BH_StartDate >= T.BH_SendDate)) % 60),2)
--) AS TotalPlaytimeHours,
( Isnull((SELECT Sum(bh_playtime)
FROM bh_historic_report_taskaudit
WHERE ( bh_taskguid = T.bh_taskguid )
AND ( bh_userguid = T.bh_authorguid )
AND ( bh_startdate >= T.bh_senddate )), 0) ) AS
'Author Play Time (Sec)',
-- (ISNULL((
-- RIGHT('00' + CONVERT(VARCHAR, (SELECT sum(BH_PlayTime)
-- FROM BH_HISTORIC_REPORT_TASKAUDIT
-- WHERE (BH_TaskGuid = T.BH_TaskGuid) AND (BH_UserGuid = T.BH_AuthorGuid) AND (BH_StartDate >= T.BH_SendDate)) / 3600 % 24),2) + ':'
-- + RIGHT('00' + CONVERT(VARCHAR, (SELECT sum(BH_PlayTime)
-- FROM BH_HISTORIC_REPORT_TASKAUDIT
-- WHERE (BH_TaskGuid = T.BH_TaskGuid) AND (BH_UserGuid = T.BH_AuthorGuid) AND (BH_StartDate >= T.BH_SendDate)) / 60 % 60),2) + ':'
-- + RIGHT('00' + CONVERT(VARCHAR,(SELECT sum(BH_PlayTime)
-- FROM BH_HISTORIC_REPORT_TASKAUDIT
-- WHERE (BH_TaskGuid = T.BH_TaskGuid) AND (BH_UserGuid = T.BH_AuthorGuid) AND (BH_StartDate >= T.BH_SendDate)) % 60),2)), '00:00:00' )
-- ) AS AuthorPlaytimeHours,
( Isnull((SELECT Sum(bh_playtime)
FROM bh_historic_report_taskaudit
WHERE ( bh_taskguid = T.bh_taskguid )
AND ( bh_userguid <> T.bh_authorguid )
AND ( bh_startdate >= T.bh_senddate )), 0) ) AS
'Non-Author Play Time (Sec)'
--(ISNULL((
-- RIGHT('00' + CONVERT(VARCHAR, (SELECT sum(BH_PlayTime)
-- FROM BH_HISTORIC_REPORT_TASKAUDIT
-- WHERE (BH_TaskGuid = T.BH_TaskGuid) AND (BH_UserGuid <> T.BH_AuthorGuid) AND (BH_StartDate >= T.BH_SendDate)) / 3600 % 24),2) + ':'
--+ RIGHT('00' + CONVERT(VARCHAR, (SELECT sum(BH_PlayTime)
-- FROM BH_HISTORIC_REPORT_TASKAUDIT
-- WHERE (BH_TaskGuid = T.BH_TaskGuid) AND (BH_UserGuid <> T.BH_AuthorGuid) AND (BH_StartDate >= T.BH_SendDate)) / 60 % 60),2) + ':'
--+ RIGHT('00' + CONVERT(VARCHAR,(SELECT sum(BH_PlayTime)
-- FROM BH_HISTORIC_REPORT_TASKAUDIT
-- WHERE (BH_TaskGuid = T.BH_TaskGuid) AND (BH_UserGuid <> T.BH_AuthorGuid) AND (BH_StartDate >= T.BH_SendDate)) % 60),2)
--), '00:00:00')) AS NonAuthorPlaytimeHours,
FROM bh_historic_report_tasks AS T
INNER JOIN bh_historic_report_users AS Auth
ON ( T.bh_authorguid = Auth.bh_userguid )
LEFT OUTER JOIN bh_historic_report_users AS Sec
ON ( T.bh_completedby = Sec.bh_userguid )
INNER JOIN bh_historic_report_departments AS AuthDept
ON ( T.bh_authordept = AuthDept.bh_departmentguid )
LEFT OUTER JOIN bh_historic_report_departments AS SecDept
ON ( T.bh_completedbydept = SecDept.bh_departmentguid )
INNER JOIN bh_historic_report_workflows AS WF
ON ( T.bh_workflowguid = WF.bh_workflowguid )
LEFT OUTER JOIN (SELECT NULL AS Availability,
A.bh_documenttypeguid,
A.bh_documenttypename,
A.bh_workflowguid,
WF.bh_workflowname,
A.bh_usage
FROM bh_documenttypes AS A
INNER JOIN bh_historic_report_workflows AS WF
ON ( A.bh_workflowguid =
WF.bh_workflowguid )
WHERE ( bh_isglobal = '1'
AND bh_deleted = 0
AND bh_disabled = 0 )
UNION
SELECT DocTypeDept.bh_departmentguid AS Availability,
DOCTYPE.bh_documenttypeguid,
DOCTYPE.bh_documenttypename,
DOCTYPE.bh_workflowguid,
WFLOW.bh_workflowname,
DOCTYPE.bh_usage
FROM bh_documenttypebydepartment AS DOCTYPEDEPT
INNER JOIN bh_documenttypes AS DOCTYPE
ON ( DOCTYPE.bh_documenttypeguid =
DOCTYPEDEPT.bh_documenttypeguid )
LEFT OUTER JOIN bh_historic_report_workflows AS
WFLOW
ON ( DOCTYPE.bh_workflowguid =
WFLOW.bh_workflowguid )
WHERE DOCTYPEDEPT.bh_departmentguid IN
(SELECT DISTINCT tempT.bh_authordept
FROM
bh_historic_report_tasks AS TempT
WHERE
--TempT.BH_SendDate >='20170901'
TempT.bh_completiondate >= #FROMDATE
--Only include tasks sent after a certain date (FORMAT = YYYYMMDD)
AND TempT.bh_completiondate < #TODATE
--Only include tasks sent after a certain date (FORMAT = YYYYMMDD)
)
AND DOCTYPE.bh_deleted = 0
AND DOCTYPE.bh_disabled = 0) AS DT
ON ( T.bh_documenttype = DT.bh_documenttypename )
AND ( ( DT.availability = AuthDept.bh_departmentguid )
OR ( DT.availability IS NULL ) )
AND ( DT.bh_usage = ( CASE
WHEN ( T.bh_source = '15' )
-- Sent from Now client
OR ( T.bh_lengthintenths =
'0'
AND T.bh_source = '18'
)
----OR sent from Hub and zero length
THEN '2' --NOW TYPE
ELSE '1' --VOICE TYPE
END ) )
--Joining on latest Audit row for the task so can return things like the latest Workflow stage etc.
INNER JOIN (SELECT bh_taskguid,
Max(bh_auditid) AS AuditID,
Count(DISTINCT bh_requiredby) RequiredBy,
Count(DISTINCT bh_priorityname) Priorities
FROM bh_historic_report_taskaudit
GROUP BY bh_taskguid) TA
ON T.bh_taskguid = TA.bh_taskguid
INNER JOIN bh_historic_report_taskaudit TAUD
ON TA.auditid = TAUD.bh_auditid
WHERE
--T.BH_CompletionDate IS NOT NULL --Include completed tasks only AND
--T.BH_CompletedByDept IS NOT NULL--Excludes Drafts created but not submitted--changed from--AND SecDept.BH_DepartmentName IS NOT NULL AND
T.bh_completiondate >= #FROMDATE
--Only include tasks created after a certain date (FORMAT = YYYYMMDD)
AND T.bh_completiondate < #TODATE
--Only include tasks created after a certain date (FORMAT = YYYYMMDD)
AND TAUD.bh_startdate >= Dateadd(month, -1, #FROMDATE)
AND TAUD.bh_startdate <= Dateadd(month, 1, #TODATE) --only includes processing audit times for activities started within 1 month prior to and post the Completion Date range
Power BI constructs a query like this:
select * from ( ... your query goes here ... ) as SourceQuery
So when it puts your query between the parenthesis, it isn't a valid query anymore. Power BI does that, because it needs to be able to add joins and filters to your query. Either rebuild the logic inside Power BI using M and DAX, or put your query in a view/UDF in the data source and select from it.

How to write valid If clause inside select or write function

I have procedure like this and I get error in If clause. I think it is because COUNT. But my clause have to be like that so I don't know how to solve it. Maybe it would be good to create a function or something similar. Rest of the code is okay
CREATE PROCEDURE DohvatiSveUgovore #zavodId int
AS
BEGIN
DECLARE #TempUgovori TABLE
(
Id int,
UstrojstvenaJedinica nvarchar(100),
VrstaUgovora nvarchar(100),
KlasaUgovora nvarchar(100),
UrudzbeniBrojUgovora nvarchar(100),
DatumPocetkaUgovora nvarchar(10),
DatumIstekaUgovora nvarchar(10)
)
INSERT INTO #TempUgovori(Id, UstrojstvenaJedinica, VrstaUgovora, KlasaUgovora, UrudzbeniBrojUgovora, DatumPocetkaUgovora, DatumIstekaUgovora)
SELECT
u.Id,
ISNULL(STRING_AGG(LTRIM(RTRIM(z.SkraceniNaziv)), ', '), '') AS 'UstrojstvenaJedinica',
vu.Naziv AS 'VrstaUgovora',
ISNULL(u.KlasaUgovora, '') AS 'KlasaUgovora',
ISNULL(u.UrudzbeniBrojUgovora, '') AS 'UrudzbeniBrojUgovora',
(SELECT ISNULL(convert(varchar(10), u.DatumPocetkaUgovora, 104), '')) AS 'DatumPocetkaUgovora',
(SELECT ISNULL(convert(varchar(10), u.DatumIstekaUgovora, 104), '')) AS 'DatumIstekaUgovora'
FROM Ugovor AS u
LEFT JOIN VezaUgovorUstrojstvenaJedinica AS vuu
ON u.Id = vuu.UgovorId
INNER JOIN SifVrstaUgovora AS vu
ON u.VrstaUgovoraId = vu.Id
LEFT JOIN [TEST_MaticniPodaci2].hcphs.SifZavod AS z
ON vuu.UstrojstvenaJedinicaId = z.Id
if( (SELECT COUNT(UstrojstvenaJedinicaId) FROM VezaUgovorUstrojstvenaJedinica WHERE UstrojstvenaJedinicaId = 'HCPHS') = 1)
begin
(SELECT * FROM VezaUgovorUstrojstvenaJedinica WHERE UstrojstvenaJedinicaId = 'HCPHS')
end
ELSE
(SELECT * FROM VezaUgovorUstrojstvenaJedinica WHERE Isdeleted = 0 and UstrojstvenaJedinicaId = #zavodId)
end
ERROR is here in Group by and I don't know why.
GROUP BY u.Id, vu.Naziv, u.KlasaUgovora, u.UrudzbeniBrojUgovora, u.DatumPocetkaUgovora, u.DatumIstekaUgovora
SELECT
tu.Id,
tu.UstrojstvenaJedinica AS 'UstrojstvenaJedinica',
tu.VrstaUgovora AS 'VrstaUgovora',
tu.KlasaUgovora AS 'KlasaUgovora',
tu.UrudzbeniBrojUgovora AS 'UrudzbeniBrojUgovora',
tu.DatumIstekaUgovora AS 'DatumPocetkaUgovora',
tu.DatumIstekaUgovora AS 'DatumIstekaUgovora',
ISNULL(STRING_AGG(LTRIM(RTRIM(p.Naziv)), ', '), '') as 'Partner'
FROM #TempUgovori AS tu
LEFT JOIN VezaUgovorPartner AS vup
on tu.Id = vup.UgovorId
LEFT JOIN [TEST_MaticniPodaci2].dbo.Partner as p
ON vup.PartnerId = p.PartnerID
GROUP BY tu.Id, tu.UstrojstvenaJedinica, tu.VrstaUgovora, tu.KlasaUgovora, tu.UrudzbeniBrojUgovora, tu.DatumPocetkaUgovora, tu.DatumIstekaUgovora
END
EXEC [TEST_Ugovori_Prod].[dbo].[DohvatiSve] 6;
GO
I am sorry for too much code but without it I can't run query.
It looks like you're trying to tell SQL Server to join to VezaUgovorUstrojstvenaJedinica differently depending on the circumstances. The sql engine can't figure that out. For a very brief discussion on how sql evaluates a query, here's a start:
https://social.msdn.microsoft.com/Forums/sqlserver/en-US/70efeffe-76b9-4b7e-b4a1-ba53f5d21916/order-of-execution-of-sql-queries?forum=transactsql
Maybe something like this will work for you?
CREATE PROCEDURE DohvatiSveUgovore #zavodId int
AS
BEGIN
DECLARE #TempUgovori TABLE
(
Id int,
UstrojstvenaJedinica nvarchar(100),
VrstaUgovora nvarchar(100),
KlasaUgovora nvarchar(100),
UrudzbeniBrojUgovora nvarchar(100),
DatumPocetkaUgovora nvarchar(10),
DatumIstekaUgovora nvarchar(10)
);
DECLARE #HCPHS integer;
SELECT
#HCPHS = COUNT(UstrojstvenaJedinicaId)
FROM
VezaUgovorUstrojstvenaJedinica
WHERE
UstrojstvenaJedinicaId = 'HCPHS';
IF #HCPHS = 1
INSERT INTO #TempUgovori(Id, UstrojstvenaJedinica, VrstaUgovora, KlasaUgovora, UrudzbeniBrojUgovora, DatumPocetkaUgovora, DatumIstekaUgovora)
SELECT
u.Id,
ISNULL(STRING_AGG(LTRIM(RTRIM(z.SkraceniNaziv)), ', '), '') AS 'UstrojstvenaJedinica',
vu.Naziv AS 'VrstaUgovora',
ISNULL(u.KlasaUgovora, '') AS 'KlasaUgovora',
ISNULL(u.UrudzbeniBrojUgovora, '') AS 'UrudzbeniBrojUgovora',
(SELECT ISNULL(convert(varchar(10), u.DatumPocetkaUgovora, 104), '')) AS 'DatumPocetkaUgovora',
(SELECT ISNULL(convert(varchar(10), u.DatumIstekaUgovora, 104), '')) AS 'DatumIstekaUgovora'
FROM Ugovor AS u
LEFT JOIN VezaUgovorUstrojstvenaJedinica AS vuu
ON u.Id = vuu.UgovorId
INNER JOIN SifVrstaUgovora AS vu
ON u.VrstaUgovoraId = vu.Id
LEFT JOIN [TEST_MaticniPodaci2].hcphs.SifZavod AS z
ON vuu.UstrojstvenaJedinicaId = z.Id
<JOIN OF SOME KIND>
(SELECT * FROM VezaUgovorUstrojstvenaJedinica WHERE UstrojstvenaJedinicaId = 'HCPHS')
ON <SOME CRITERIA>
GROUP BY u.Id, vu.Naziv, u.KlasaUgovora, u.UrudzbeniBrojUgovora, u.DatumPocetkaUgovora, u.DatumIstekaUgovora
ELSE
INSERT INTO #TempUgovori(Id, UstrojstvenaJedinica, VrstaUgovora, KlasaUgovora, UrudzbeniBrojUgovora, DatumPocetkaUgovora, DatumIstekaUgovora)
SELECT
u.Id,
ISNULL(STRING_AGG(LTRIM(RTRIM(z.SkraceniNaziv)), ', '), '') AS 'UstrojstvenaJedinica',
vu.Naziv AS 'VrstaUgovora',
ISNULL(u.KlasaUgovora, '') AS 'KlasaUgovora',
ISNULL(u.UrudzbeniBrojUgovora, '') AS 'UrudzbeniBrojUgovora',
(SELECT ISNULL(convert(varchar(10), u.DatumPocetkaUgovora, 104), '')) AS 'DatumPocetkaUgovora',
(SELECT ISNULL(convert(varchar(10), u.DatumIstekaUgovora, 104), '')) AS 'DatumIstekaUgovora'
FROM Ugovor AS u
LEFT JOIN VezaUgovorUstrojstvenaJedinica AS vuu
ON u.Id = vuu.UgovorId
INNER JOIN SifVrstaUgovora AS vu
ON u.VrstaUgovoraId = vu.Id
LEFT JOIN [TEST_MaticniPodaci2].hcphs.SifZavod AS z
ON vuu.UstrojstvenaJedinicaId = z.Id
<JOIN OF SOME KIND>
(SELECT * FROM VezaUgovorUstrojstvenaJedinica WHERE Isdeleted = 0 and UstrojstvenaJedinicaId = #zavodId)
ON <SOME CRITERIA>
GROUP BY u.Id, vu.Naziv, u.KlasaUgovora, u.UrudzbeniBrojUgovora, u.DatumPocetkaUgovora, u.DatumIstekaUgovora

Case when exists - column (SQL)

I'm trying to populate the field of an XML file with either '0', if a specific column (pv_an4) does not exist, OR with the value of the column, if it exists.
This is my code so far:
XMLELEMENT( Name "Telephone",
case
when not exists (SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'phonebook' AND COLUMN_NAME = 'pv_an4') then ''
when exists (SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'phonebook' AND COLUMN_NAME = 'pv_an4') then pv_an4
end ),
When I execute this I get this error:
FEHLER: Column »pv_an4« does not exist ZEILE 25: ...E_NAME =
'phonebook' AND COLUMN_NAME = 'pv_an4') then pv_an4
But this does make no sense to me, because for example with this code it would work:
....
when exists (SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'phonebook' AND COLUMN_NAME = 'pv_an4') then 'pv_an4 exists'
end ),
....
I've spent the whole day trying to solve this problem, could someone hint me in the right direction, please?
/edit: Full query right below:
SELECT
XMLFOREST( xmlpb.entry as "DivinusIPPhoneDirectory" )
FROM (
SELECT
XMLCONCAT (
XMLELEMENT ( NAME "Title", 'Phonelist' ),
XMLELEMENT ( NAME "Prompt", 'Prompt' ),
XMLAGG (
XMLELEMENT (
NAME "DirectoryEntry",
XMLELEMENT( Name "Name",
case
when (pb.company = '') IS FALSE AND pb.lastname != '' and pb.firstname != '' then pb.company || ' - ' || pb.lastname || ', ' || pb.firstname
when (pb.company = '') IS FALSE AND pb.lastname != '' and pb.firstname = '' then pb.company || ' - ' || pb.lastname
when (pb.company = '') IS FALSE AND pb.lastname = '' and pb.firstname = '' then pb.company
when (pb.company = '') IS FALSE AND pb.lastname = '' and pb.firstname != '' then pb.company || ' - ' || pb.firstname
when (pb.company = '') IS NOT FALSE AND pb.lastname != '' and pb.firstname != '' then pb.lastname || ', ' || pb.firstname
when (pb.company = '') IS NOT FALSE AND pb.lastname != '' and pb.firstname = '' then pb.lastname
end ),
XMLELEMENT( Name "Telephone", pb.pv_an3 ),
XMLELEMENT( Name "Telephone",
case
when not exists (SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'phonebook' AND COLUMN_NAME = 'pv_an4') then ''
else pb.pv_an4
end ),
XMLELEMENT( Name "Telephone", pb.phonenumber ),
XMLELEMENT( Name "Telephone", pb.pv_an1 ),
XMLELEMENT( Name "Telephone", pb.pv_an2 )
)
)
) as entry
FROM
phonebook pb
WHERE fkidtenant = 1
The whole sql statement is parsed and compiled before it is run, therefore postgresql will complain of the missing field. There is no shortcut.
You need to use dynamically generated sql if you want to handle such scenarios (check whether the column exists and create the appropriate sql statement). Although I cannot really imagine why you should not know if a certain column exists in a table or not.
Try:
XMLELEMENT( Name "Telephone",
case
when not exists (SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'phonebook' AND COLUMN_NAME = 'pv_an4') then ''
when exists (SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'phonebook' AND COLUMN_NAME = 'pv_an4') then 'pv_an4'
end ),
In line 4, you're using pv_an4 as a column in your first query, but as a column value in your second query.

T-SQL to check and update

Getting error:
Msg 512, Level 16, State 1, Line 48
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
Msg 512, Level 16, State 1, Line 87
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
Need to check each record in the table and update a table if there is no records = to 0,00. Then update an existing table with current values. I want to be able to track current data and compare with old data.
DECLARE #LocTime DATETIME;
DECLARE #MinDateTime DATETIME;
DECLARE #SystemDateTime DATETIME;
DECLARE #LIR MONEY;
DECLARE #LOAR MONEY;
SELECT #SystemDateTime = SYSDATETIME(); --= '2016-12-07 23:30:00'
SELECT #MinDateTime = DATEADD(mi,-30,#SystemDateTime) --go back half hour of reads, job is running every 10 minutes for overlap
--select #MinDateTime, #SystemDateTime
IF OBJECT_ID(N'tempdb..##LastOver2') IS NOT NULL
BEGIN
DROP TABLE ##LastOver2
END
--make temp table to hold found data
CREATE TABLE ##LastOver2 (ReadDate DATETIME
, FacilityName NVARCHAR(100)
, FacilityID UNIQUEIDENTIFIER
, LastInstantRead MONEY
, LastOverAllRead MONEY
, FacilityTimeZone INT
, FacilityTime DATETIME)
INSERT INTO ##LastOver2 (ReadDate, FacilityName
, FacilityID, LastInstantRead
, LastOverAllRead
, FacilityTimeZone, FacilityTime)
SELECT DISTINCT --why distinct?
fmr.ReadDate, f.Name
, f.FacilityID, fm.LastInstantRead
, fm.LastOverAllRead
, f.Timezone
, #LocTime
FROM [dbo].[Facilities] f WITH (NOLOCK)
JOIN [dbo].[FacilityMeters] fm WITH (NOLOCK)
ON F.FacilityID = FM.FacilityID
JOIN FacilityMeterReadings fmr WITH (NOLOCK)
ON FM.FacilityMeterID = FMR.FacilityMeterID
WHERE --fm.FacilityMeterID = '9268d1af-cc29-432c-9cdb-06c158180d2f'
(fmr.ReadDate >= #MinDateTime and ReadDate <= #SystemDateTime) --including on both side to continue with overlap
and (fm.IsVirtual = 0 and fm.ParentMeterID is NULL)
--and (fm.LastInstantRead = 0.00 and fm.LastOverAllRead = 0.00)
AND f.SuppressMonitoring = 0
select * from ##LastOver2
IF (select LastInstantRead from ##LastOver2) = 0.00 OR (SELECT LastOverAllRead FROM ##LastOver2) = 0.00
BEGIN
--UPDATE dbo.Facilities
--SET SuppressMonitoring = 1
-- FROM dbo.Facilities F
-- JOIN ##LastOver L
-- ON F.FacilityID = l.FacilityID
-- WHERE F.FacilityID = l.FacilityID
DECLARE #body_content NVARCHAR(150);
DECLARE #StartHour NVARCHAR(8) = '08:30:00' ;
DECLARE #StopHour NVARCHAR(8) = '16:00:00';
--why distinct, is it already distinct. Is is supposed to distinct the facility or meter?
DECLARE #SQLScript NVARCHAR(200) = 'SELECT distinct * FROM ##LastOver2 WHERE CONVERT(TIME, FacilityTime) BETWEEN '
+ CHAR(39) + #StartHour + CHAR(39) +' AND ' + CHAR(39) + #StopHour + CHAR(39);
--only looking for reads during day hours? shouldn't use between.
DECLARE #copyRecipients NVARCHAR(100)
SET #body_content = 'Please check the attached file. This was from server: ' + ##SERVERNAME
DECLARE #fileName nvarchar(255);
select #fileName = 'BadReading_' + replace(replace(convert(nvarchar(19),getdate(), 126),':',''),'-','') + '.txt';
EXEC msdb.dbo.sp_send_dbmail
#profile_name = 'SQLSupport'
,#recipients = 'Btest#test.com'
--, #recipients = 'jira#cleanenergycollective.atlassian.net'
--, #copy_recipients= #copyRecipients
--, #copy_recipients= 'Bill.Lugaila#easycleanenergy.com;yvonne.lewis#easycleanenergy.com;don.munroe#easycleanenergy.com;Justin.Reed#easycleanenergy.com'
, #query = #SQLScript
, #subject = 'Facility Meter Check and Updating table' --change so easier to see in emails
, #body= #body_content
, #importance= 'High'
, #attach_query_result_as_file = 1
, #query_attachment_filename = #fileName ;
--select #SQLScript
END
ELSE IF (select LastInstantRead from ##LastOver2) != 0.00 OR (SELECT LastOverAllRead FROM ##LastOver2) != 0.00
BEGIN
UPDATE [dbo].[_LastInstant_OverAll_Read]
SET [FacilityName] = lo.FacilityName,
[LastInstantRead] = lo.LastInstantRead,
[LastOverAllRead]= lo.LastOverAllRead,
[Time_Date] = (SELECT CONVERT(DateTime, SysDateTime()))
FROM ##LastOver2 lo
WHERE lo.FacilityName = [dbo].[_LastInstant_OverAll_Read].FacilityName
AND lo.LastInstantRead != [dbo].[_LastInstant_OverAll_Read].LastInstantRead
AND lo.LastOverAllRead != [dbo].[_LastInstant_OverAll_Read].LastOverAllRead
END
the following could be returning multiple rows:
.
.
.
IF
(
SELECT LastInstantRead
FROM ##LastOver2
) = 0.00
OR
(
SELECT LastOverAllRead
FROM ##LastOver2
) = 0.00
.
.
.
IF
(
SELECT LastInstantRead
FROM ##LastOver2
) != 0.00
OR
(
SELECT LastOverAllRead
FROM ##LastOver2
) != 0.00
if you are expecting them to return only 1 row then you will need to fix the issue with the following query:
SELECT DISTINCT --why distinct?
fmr.ReadDate,
f.Name,
f.FacilityID,
fm.LastInstantRead,
fm.LastOverAllRead,
f.Timezone,
#LocTime
FROM [dbo].[Facilities] f WITH (NOLOCK)
JOIN [dbo].[FacilityMeters] fm WITH (NOLOCK) ON F.FacilityID = FM.FacilityID
JOIN FacilityMeterReadings fmr WITH (NOLOCK) ON FM.FacilityMeterID = FMR.FacilityMeterID
WHERE --fm.FacilityMeterID = '9268d1af-cc29-432c-9cdb-06c158180d2f'
(fmr.ReadDate >= #MinDateTime
AND ReadDate <= #SystemDateTime) --including on both side to continue with overlap
AND (fm.IsVirtual = 0
AND fm.ParentMeterID IS NULL)
--and (fm.LastInstantRead = 0.00 and fm.LastOverAllRead = 0.00)
AND f.SuppressMonitoring = 0;

tsql to generate index creation text, then evaluate it

I have a script that creates and populates a bunch of tables from data we receive as
text files. After loading the data into sql server 2008, I want to add indexes. The cut-and-paste-created script I'm using is shown below.
Is
there a way in TSQL to create a function that will generate and then
evaluate the DDL commands? The function would take parameters
of table name, column name(s) and clustered/not. If there would have
to be a separate function for 1 column/2 column indexes, I'd still
be interested.
I'm envisioning something like:
hypotheticalFunction('clustered', 'precCdaEarn', 'account', 'seq')
hypothericalFunction('nonClustered', 'flats', 'vendorAcct')
and that would check if an acct called "idx_acct_seq" exists on table
precCdaEarn, and drop it if so, then create it as clustered index. (dropping it just
in case i change the definition). And create/recreate a nonclustered index on dbo.flats named "idx_vendorAcct"
========= this is what have now using cut & paste, apologies for the erratic spacing ==============
IF EXISTS (Select 'X'
FROM sysindexes
WHERE id = (SELECT OBJECT_ID('precCdaEarn'))
and name = 'idx_account_seq')
DROP index precCdaEarn.idx_account_seq
Create nonclustered index idx_account_seq
ON precCdaEarn(account, seq)
;
IF EXISTS (Select 'X'
FROM sysindexes
WHERE id = (SELECT OBJECT_ID('acct'))
and name = 'idx_c_precAcct_precMod')
DROP index acct.idx_c_precAcct_precMod
CREATE CLUSTERED INDEX index idx_c_precAcct_precMod
ON acct(precAcct, precMod)
AFAIK you cannot create a function for this, but with a stored procedure it's no problems.
Something like:
IF(OBJECT_ID('PRC_CREATE_INDEX', N'P') IS NOT NULL)
DROP PROCEDURE PRC_CREATE_INDEX
GO
CREATE PROCEDURE dbo.PRC_CREATE_INDEX
(
-- Table name to add index to
#pTablename AS VARCHAR(120)
-- Index name to add/change
, #pIndexname AS VARCHAR(120)
-- UNIQUE, CLUSTERED or other definition
, #pNewIndexDef AS VARCHAR(255) = ''
-- Columns in index
, #pNewIndexCols AS VARCHAR(255)
-- Recreate even if same
, #pForceRecreate AS SMALLINT = 0
-- Additional columns for INCLUDE
, #pColumnsInclude AS VARCHAR(255) = ''
)
AS
------------------------------------
-- Variabels
------------------------------------
DECLARE #SQL_DROP AS NVARCHAR(1000)
, #SQL_CREATE AS NVARCHAR(1000)
, #retval AS INTEGER
, #rowcount AS INTEGER
DECLARE #oldDescription AS VARCHAR(255)
, #newUnique AS SMALLINT
, #newClustered AS SMALLINT
, #newIndexDef AS VARCHAR(255)
, #newDescription AS VARCHAR(255)
, #drop_index AS BIT
, #temp AS VARCHAR(MAX)
------------------------------------
-- Initiate
------------------------------------
SET XACT_ABORT ON
SET NOCOUNT ON
-- Table exists?
IF(OBJECT_ID(#pTablename) IS NULL)
BEGIN
PRINT 'Error: Table does not exist: ' + #pTablename +
' (' + 'creation of index ''' + #pTablename + '.' + #pIndexname + ''')'
RETURN (1)
END
-----------------------------------------------------------------------------------------------------
-- New index
-----------------------------------------------------------------------------------------------------
-- Initiate (Remove blanks, get unique/clustered info)
SELECT #newIndexDef = #pNewIndexDef
-- Remove NONCLUSTERED
, #newIndexDef = REPLACE(#newIndexDef, 'nonclustered', '')
-- CLUSTERED?
, #newClustered = CASE WHEN PATINDEX('%clustered%', LOWER(#newIndexDef)) > 0 THEN 1 ELSE 0 END
, #newIndexDef = REPLACE(#newIndexDef, 'clustered', '')
-- UNIQUE?
, #newUnique = CASE WHEN PATINDEX('%unique%', LOWER(#pNewIndexDef)) > 0 THEN 1 ELSE 0 END
, #newIndexDef = REPLACE(#newIndexDef, 'unique', '')
-- Remove blanks etc.
, #pNewIndexCols = REPLACE(#pNewIndexCols, ' DESC', '#DESC')
, #newIndexDef = REPLACE(#newIndexDef, ' ', '')
, #newIndexDef = REPLACE(#newIndexDef, ',', '')
, #pNewIndexCols = REPLACE(#pNewIndexCols, ' ', '')
, #pColumnsInclude = REPLACE(#pColumnsInclude, ' ', '')
-- Correct defintion?
IF LEN(#newIndexDef) > 0
BEGIN
RAISERROR ('Index defintion ''%s'' is incorrect for index ''%s.%s''!', 11, 11, #pNewIndexDef, #pTablename, #pIndexname)
RETURN (1)
END
IF #newClustered = 1 AND LEN(#pColumnsInclude) > 0
BEGIN
RAISERROR ('Cannot specify included columns for a clustered index (''%s.%s'')!', 11, 11, #pIndexname, #pTablename)
RETURN (1)
END
IF #pNewIndexCols LIKE '%#DESC%'
BEGIN
RAISERROR ('Descending sort direction not supported (''%s.%s'')!', 11, 11, #pTablename, #pIndexname)
RETURN (1)
END
IF #newClustered = 1 AND EXISTS
(
SELECT 1
FROM sys.indexes (NOLOCK)
WHERE object_id = OBJECT_ID(#pTablename, N'U')
AND name <> #pIndexname
AND type = 1 -- CLUSTERED
AND is_hypothetical = 0
)
BEGIN
SELECT #temp = name
FROM sys.indexes (NOLOCK)
WHERE object_id = OBJECT_ID(#pTablename, N'U')
AND name <> #pIndexname
AND type = 1 -- CLUSTERED
AND is_hypothetical = 0
RAISERROR ('Cannot add CLUSTERED index (''%s.%s'') - table already has a clustered index (''%s'')!', 11, 11, #pTablename, #pIndexname, #temp)
RETURN (1)
END
-- Prepare SQL
-- CREATE
SELECT #SQL_CREATE = ''
+ 'CREATE '
+ CASE WHEN #newUnique = 1 THEN 'UNIQUE ' ELSE '' END
+ CASE WHEN #newClustered = 1 THEN 'CLUSTERED ' ELSE 'NONCLUSTERED ' END
+ 'INDEX ' + #pIndexname + ' '
+ 'ON ' + #pTablename + ' '
+ '(' + #pNewIndexCols + ')'
+ CASE WHEN LEN(#pColumnsInclude) > 0 THEN ' INCLUDE (' + #pColumnsInclude + ')' ELSE '' END
-- Description
SELECT #newDescription = ''
+ CASE WHEN #newUnique = 1 THEN 'UNIQUE ' ELSE '' END
+ CASE WHEN #newClustered = 1 THEN 'CLUSTERED ' ELSE 'NONCLUSTERED ' END
+ '(' + #pNewIndexCols + ')'
+ CASE WHEN LEN(#pColumnsInclude) > 0 THEN ' INCLUDE (' + #pColumnsInclude + ')' ELSE '' END
-- DROP
SET #SQL_DROP = ''
+ 'DROP INDEX ' + #pTablename
+ '.' + #pIndexname
-----------------------------------------------------------------------------------------------------
-- Current index
-----------------------------------------------------------------------------------------------------
-- Initiate
SELECT #drop_index = 0
-- Get definition/description and check if recreation is needed
IF EXISTS
(
SELECT 1
FROM sys.indexes (NOLOCK)
WHERE object_id = OBJECT_ID(#pTablename, N'U')
AND name = #pIndexname
)
BEGIN
-- Description
SELECT #oldDescription = ''
+ CASE WHEN i.is_unique = 1 THEN 'UNIQUE ' ELSE '' END
+ CASE
WHEN i.type = 1 THEN 'CLUSTERED '
WHEN i.type = 2 THEN 'NONCLUSTERED '
ELSE '? '
END
+ '(' + STUFF(
(
SELECT ',' + COL_NAME(ic.object_id, ic.column_id)
FROM sys.index_columns ic (NOLOCK)
WHERE ic.object_id = i.object_id
AND ic.index_id = i.index_id
AND ic.is_included_column = 0
ORDER BY ic.key_ordinal
FOR XML PATH('')
)
, 1, 1, '') + ')'
+ ISNULL(' INCLUDE (' + STUFF(
(
SELECT ',' + COL_NAME(ic.object_id, ic.column_id)
FROM sys.index_columns ic (NOLOCK)
WHERE ic.object_id = i.object_id
AND ic.index_id = i.index_id
AND ic.is_included_column = 1
ORDER BY ic.index_column_id -- Or column_id???
FOR XML PATH('')
)
, 1, 1, '') + ')', '')
FROM sys.indexes i (NOLOCK)
WHERE i.object_id = OBJECT_ID(#pTablename, N'U')
AND i.name = #pIndexname
-- Exit?
-- If not changed and no force of recreation
IF #oldDescription = #newDescription
AND
#pForceRecreate = 0
BEGIN
RETURN 0
END
-- We should drop current index..
SET #drop_index = 1
END
-----------------------------------------------------------------------------------------------------
-- Execute SQL
-----------------------------------------------------------------------------------------------------
-- Exec
IF #drop_index = 1
EXEC sp_executesql #SQL_DROP
IF LEN(#pNewIndexCols) > 0
EXEC sp_executesql #SQL_CREATE
-- Message
IF LEN(#pNewIndexCols) > 0 AND #drop_index = 0
PRINT 'Created index ' + #pTablename + '.' + #pIndexname + ' (' + #newDescription + ')'
ELSE IF LEN(#pNewIndexCols) > 0 AND #drop_index = 1
PRINT 'Recreated index ' + #pTablename + '.' + #pIndexname + CHAR(10) +
' From: ' + #oldDescription + CHAR(10) +
' To: ' + #newDescription
-- Well, this will perhaps occur when and if this proc is changed...
ELSE IF #drop_index = 1
PRINT 'Removed index ' + #pTablename + '.' + #pIndexname + ' (' + #oldDescription + ')'
-----------------------------------------------------------------------------------------------------
-- Exit
-----------------------------------------------------------------------------------------------------
RETURN (0)
GO
Use it like:
EXEC dbo.PRC_CREATE_INDEX
#pTablename = 'someTable'
, #pIndexname = 'idx_someTable'
, #pNewIndexDef = 'CLUSTERED'
, #pNewIndexCols = 'some, columns, listed'