The below stored procedure works for SQL Server (before I made some oracle specific changes).
Now this stored procedure must work for Oracle too.
The Oracle Sql Developer which I use complains at the line after the "OPEN CURSOR_ FOR"
Somehow Oracle does not like that I 'group' both select statements and the union and do on this whole result an order by...
What do I wrong? I only know a bit about oracle stored procedures...
create or replace
PROCEDURE GetWorkflowStatusForMatrix(
p_ApplicationId IN varchar2,
CURSOR_ OUT sys_refcursor
)
AS
BEGIN
OPEN CURSOR_ FOR
(
select ApplicationId || ModuleId || UNIT_ID as StatusKey, UNIT_ID, ApplicationId, ModuleId, Owner, "Level", Action, "Comment", LastModifiedUser, LastModifiedDate
from WorkflowStatus where ApplicationId = p_ApplicationId
union
select distinct e.ApplicationId + WorkflowId + UnitId as StatusKey, UnitId, e.ApplicationId, WorkflowId, w.Owner, 'Level1', 'Working', EventType, UserId, EventDateTime as LastModifiedDate
from EventLog e
join WorkflowStatus w on w.ApplicationId = e.ApplicationId and w.ModuleId = e.WorkflowId and w.UNIT_ID = e.UnitId
where e.ApplicationId = p_ApplicationId and w.Owner <> '' and w.Action = 'Created'
)
order by LastModifiedDate DESC;
END;
You need to read up on how to Define Cursors in Oracle - this will help you out..
http://www.techonthenet.com/oracle/cursors/declare.php
create or replace
PROCEDURE GetWorkflowStatusForMatrix(
p_ApplicationId IN varchar2,
CURSOR_ OUT sys_refcursor
)
AS
BEGIN
OPEN CURSOR_ FOR
select ApplicationId || ModuleId || UNIT_ID as StatusKey, UNIT_ID, ApplicationId, ModuleId, Owner, "Level", Action, "Comment", LastModifiedUser, LastModifiedDate
from WorkflowStatus where ApplicationId = p_ApplicationId
union
select distinct e.ApplicationId + WorkflowId + UnitId as StatusKey, UnitId, e.ApplicationId, WorkflowId, w.Owner, 'Level1', 'Working', EventType, UserId, EventDateTime as LastModifiedDate
from EventLog e
join WorkflowStatus w on w.ApplicationId = e.ApplicationId and w.ModuleId = e.WorkflowId and w.UNIT_ID = e.UnitId
where e.ApplicationId = p_ApplicationId and w.Owner <> '' and w.Action = 'Created'
order by LastModifiedDate DESC;
END;
Related
I'm writing a stored procedure which is first doing an insert if the data does not exists. If the data exists, I'm updating the date column and inserting data. When I run the stored procedure, I get the following error.
incorrect syntax near ' ; '
I don't know what is going on or what I'm doing wrong... It seems like there's something wrong with my CTE, but I don't know for sure. Thank you in advance.
CREATE PROCEDURE [dbo].[spSCDTest] #SCD [dbo].[spSCDTest1] READONLY
AS
BEGIN
/****** SCD TYPE - 2 (retains the full history of values) ******/
/** DimUsers Insert New**/
CREATE NONCLUSTERED INDEX IX_DimUsers_userID
ON [dbo].[DimUsers] ([userID]);
WITH DimCTE AS
(
SELECT * ,
HASHBYTES('SHA2_256',CONCAT(source.name,'|',source.location,'|',source.supervisor, '|',source.salary)) as [HashUsers]
FROM #SCD source
)
INSERT INTO dbo.DimUsers
(
userID,
name,
location,
StartDate,
EndDate,
supervisor,
salary,
HashUsers
)
SELECT
cte.userID,
cte.name,
cte.location,
GETDATE() AS StartDate,
'12/31/9999' AS EndDate,
cte.supervisor,
cte.salary,
cte.HashUsers
FROM
DimCTE cte
WHERE not exists
(SELECT * FROM dbo.DimUsers DU WHERE DU.userID = cte.userID);
/** DimUsers Update Old**/
CREATE NONCLUSTERED INDEX IX_Enddate_serID
ON [dbo].[DimUsers] ([EndDate], [userID])
INCLUDE([HashUsers]);
DECLARE #NewEndDate datetime2;
SET #NewEndDate = GETDATE();
WITH DimCTE AS
(
SELECT * ,
HASHBYTES('SHA2_256',CONCAT(source.name,'|',source.location,'|',source.supervisor, '|',source.salary)) as [HashUsers]
FROM #SCD source
)
UPDATE DimUsers
SET
EndDate = #NewEndDate
FROM
DimUsers DU
INNER JOIN DimCTE cte ON DU.userID = cte.userID
WHERE
(
DU.EndDate = '12/31/9999' AND
cte.HashUsers <> du.HashUsers
);
/** DimUsers InsertOld Update**/
WITH DimCTE AS
(
SELECT * ,
HASHBYTES('SHA2_256',CONCAT(source.name,'|',source.location,'|',source.supervisor, '|',source.salary)) as [HashUsers]
FROM #SCD source
)
INSERT INTO dbo.DimUsers
(
userID,
name,
location,
StartDate,
EndDate,
supervisor,
salary,
HashUsers
)
SELECT
cte.userID,
cte.name,
cte.location,
#NewEndDate AS StartDate,
'12/31/9999' AS EndDate,
cte.supervisor,
cte.salary,
cte.HashUsers
FROM
DimCTE cte
INNER JOIN DimUsers DU ON DU.userID = cte.userID AND DU.EndDate = #NewEndDate;
I've seen several similar questions but haven't found one that answers my question.
I have a source table with many individual notes for a company
CompanyName, Notes3
Company1, "spoke with someone"
Company2, "Email no longer works"
Company1, "Moved address"
I have a destination table (vchCompanyName is unique here)
vchCompanyName, vchNotes
Company1, "started business in 2005"
Company2, null
I want to end up with
vchCompanyName, vchNotes
Company1, "started business in 2005
spoke with someone
Moved address"
Company2, "Email no longer works"
I have tried this code
WITH CTE
AS (SELECT ROW_NUMBER() OVER (PARTITION BY CompanyName, Notes3 ORDER BY CompanyName) RowNum, *
FROM CompanyContact
)
merge dCompany as target
using CTE as source
on target.vchcompanyname = source.companyname
when matched and len(source.notes3)>0 and source.RowNum = 1
then
update set target.vchnote = vchnote + CHAR(13) + source.Notes3
But get the error
The MERGE statement attempted to UPDATE or DELETE the same row more than once. This happens when a target row matches more than one source row. A MERGE statement cannot UPDATE/DELETE the same row of the target table multiple times. Refine the ON clause to ensure a target row matches at most one source row, or use the GROUP BY clause to group the source rows.
Which is accurate.
I have also tried STRING_AGG but get an undefined UDF error.
How do I change my code to run iteratively?
--EDIT--
I had tried the following update code
WITH CTE
AS (SELECT ROW_NUMBER() OVER (PARTITION BY CompanyName, Notes3 ORDER BY CompanyName) RowNum, *
FROM CompanyContact
)
UPDATE dCompany SET vchNote = vchNote +
(select CHAR(13) + cc.Notes3 from CompanyContact cc
inner JOIN dCompany dc ON dc.vchCompanyName COLLATE database_default = LEFT(cc.CompanyName,50) COLLATE database_default
inner join CTE on dc.vchCompanyName COLLATE database_default = LEFT(CTE.CompanyName,50) COLLATE database_default
WHERE LEN(cc.Notes3)>0
and RowNum = 1
);
But get the error
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
#Chris Crawshaw, I will approach this by doing a 'union all' on the source and destination table to pick up all the notes for each company. Then using the STUFF function, it is easy to concatenate all the notes into one cell, while grouping by the induvidual company names. See the mockup below:
DECLARE #Source TABLE (CompanyName VARCHAR(20), Notes3 VARCHAR(50))
INSERT INTO #Source
SELECT 'Company1', 'spoke with someone' UNION ALL
SELECT 'Company2', 'Email no longer works' UNION ALL
SELECT 'Company1', 'Moved address'
DECLARE #Destination TABLE (vchCompanyName VARCHAR(20), vchNotes VARCHAR(500))
INSERT INTO #Destination
SELECT 'Company1', 'started business in 2005' UNION ALL
SELECT 'Company2', NULL
;WITH Temp AS (
SELECT *
FROM
(
SELECT *
FROM
#Destination D
WHERE D.vchNotes is not null
UNION ALL
SELECT *
FROM
#Source S
)h
)
update D
SET D.vchNotes=U.vchNotes
FROM #Destination D
LEFT JOIN(
SELECT t2.vchCompanyName, vchNotes=STUFF((
SELECT ',' + vchNotes
FROM Temp t1 where t1.vchCompanyName=t2.vchCompanyName
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1, '')
FROM
#Destination t2
GROUP BY
t2.vchCompanyName
)U ON
U.vchCompanyName=D.vchCompanyName
--TEST--
SELECT *
FROM
#Destination
I have below stored procedure in sql server 2016, its working fine there.
Now I need to create the same sp in sql 2008, now I am getting error :
Msg 102, Level 15, State 1, Procedure GetEmployees, Line 41 [Batch
Start Line 0] Incorrect syntax near 'OFFSET'. Msg 153, Level 15, State
2, Procedure GetEmployees, Line 42 [Batch Start Line 0] Invalid usage
of the option NEXT in the FETCH statement.
How to modify the same proc so that it can run over sql 2008 as well.
--dbo.GetEmployees '',2,2
CreatePROCEDURE [dbo].GetEmployees
(
#SearchValue NVARCHAR(50) = '',
#PageNo INT = 0,
#PageSize INT = 10,
#SortColumn NVARCHAR(20) = 'Name',
#SortOrder NVARCHAR(20) = 'ASC'
)
AS BEGIN
SET NOCOUNT ON;
if #PageNo<0 set #PageNo=0
set #PageNo=#PageNo+1
SET #SearchValue = LTRIM(RTRIM(#SearchValue))
Set #SearchValue= nullif(#SearchValue,'')
; WITH CTE_Results AS
(
SELECT EmployeeID, Name, City from tblEmployee
WHERE (#SearchValue IS NULL OR Name LIKE '%' + #SearchValue + '%')
ORDER BY
CASE WHEN (#SortColumn = 'EmployeeID' AND #SortOrder='ASC')
THEN EmployeeID
END ASC,
CASE WHEN (#SortColumn = 'EmployeeID' AND #SortOrder='DESC')
THEN EmployeeID
END DESC,
CASE WHEN (#SortColumn = 'Name' AND #SortOrder='ASC')
THEN Name
END ASC,
CASE WHEN (#SortColumn = 'Name' AND #SortOrder='DESC')
THEN Name
END DESC,
CASE WHEN (#SortColumn = 'City' AND #SortOrder='ASC')
THEN City
END ASC,
CASE WHEN (#SortColumn = 'City' AND #SortOrder='DESC')
THEN City
END DESC
OFFSET #PageSize * (#PageNo - 1) ROWS
FETCH NEXT #PageSize ROWS ONLY
),
CTE_TotalRows AS
(
select count(EmployeeID) as MaxRows from tblEmployee WHERE (#SearchValue IS NULL OR Name LIKE '%' + #SearchValue + '%')
)
Select MaxRows TotalRecords, t.EmployeeID, t.Name, t.City,t.Department,t.Gender from dbo.tblEmployee as t, CTE_TotalRows
WHERE EXISTS (SELECT 1 FROM CTE_Results WHERE CTE_Results.EmployeeID = t.EmployeeID)
OPTION (RECOMPILE)
END
You need a row_number() window function and in the OVER section you want to put your entire sorting expression. Note that I've created another CTE for readability, but you could get the same thing done with just a subquery.
Formatted code for the SELECT statement would be the following:
WITH CTE_Rownums AS (
SELECT
EmployeeID,
Name,
City,
row_number() over ( ORDER BY ... ) as rn -- put your entire order by here
FROM tblEmployee
WHERE
#SearchValue IS NULL
OR Name LIKE '%' + #SearchValue + '%'
), CTE_Results AS (
SELECT EmployeeID, Name, City
FROM CTE_Rownums
WHERE
(rn > #PageSize * (#PageNo - 1)
AND (rn <= #PageSize * #PageNo)
ORDER BY rn
), CTE_TotalRows AS (
SELECT count(EmployeeID) as MaxRows
FROM tblEmployee
WHERE
#SearchValue IS NULL
OR Name LIKE '%' + #SearchValue + '%'
)
SELECT MaxRows TotalRecords, t.EmployeeID, t.Name, t.City,t.Department,t.Gender
FROM dbo.tblEmployee as t
CROSS JOIN CTE_TotalRows
WHERE EXISTS (
SELECT 1
FROM CTE_Results
WHERE CTE_Results.EmployeeID = t.EmployeeID
)
OPTION (RECOMPILE)
In the last SELECT I've replaced comma separated where clause with CROSS JOIN.
If you use 2008 R2 or older you can't use OFFSET FETCH,
you have alternative to use ROW_NUMBER() and rewrite your query for examle
with OFFSET
SELECT Price
FROM dbo.Inventory
ORDER BY Price OFFSET 10 ROWS FETCH NEXT 5 ROWS ONLY
this query without OFFSET using ROW_NUMBER()
SELECT Price
FROM
(
SELECT Price
ROW_NUMBER() OVER (ORDER BY Price) AS Seq
FROM dbo.Inventory
)t
WHERE Seq BETWEEN 11 AND 15
I'm using the code below to pull 3 columns:
Server Name
Database Name
Date/Time Restore started
Code:
WITH LastRestores
AS
(
SELECT
##SERVERNAME AS [ServerName],
[d].[name] AS [DatabaseName],
CONVERT(VARCHAR, r.restore_date, 100) AS [RestoreDateTime],
RowNum = ROW_NUMBER() OVER (PARTITION BY d.NAME
ORDER BY r.[restore_date] DESC)
FROM
master.sys.databases d
LEFT OUTER JOIN
msdb.dbo.[restorehistory] r ON r.[destination_database_name] = d.NAME
)
SELECT
[ServerName], [DatabaseName], [RestoreDateTime]
FROM
[LastRestores]
WHERE
[RowNum] = 1
AND DatabaseName NOT IN ('master', 'model', 'msdb', 'tempdb')
AND CONVERT(VARCHAR(12), [RestoreDateTime]) = CONVERT(VARCHAR(12), GETDATE())
What I'd like to do is get the RunDuration that is tied in with the msdb..sysjobhistory table. I can't, for the life of me, see how to tie that table in with my code above. I'm sure there is a round about way to get the info I am looking for.
Any suggestions?
Thanks!
You can find the end datetime of a restore in the SQL Server logs. You can use xp_readerrorlog to read the logs. Please note that the format of the message may be different depending on your version. This code works in SQL Server 2012.
CREATE TABLE #t (LogDate DATETIME, ProcessInfo VARCHAR(100), RowVal VARCHAR(512));
INSERT INTO #t
EXEC master.dbo.xp_readerrorlog;
WITH RestoreDate AS (
SELECT
LEFT(REPLACE(RowVal, 'Database was restored: Database: ', ''), CHARINDEX(', creation', REPLACE(RowVal, 'Database was restored: Database: ', '')) - 1) AS DbName,
LogDate
FROM
#t
WHERE
RowVal LIKE 'Database was restored: Database: %'),
LastRestores AS (
SELECT
##SERVERNAME AS [ServerName],
[d].[name] AS [DatabaseName],
CONVERT(VARCHAR, r.restore_date, 100) AS [RestoreDateTime],
RowNum = ROW_NUMBER() OVER (PARTITION BY d.NAME
ORDER BY r.[restore_date] DESC)
FROM
master.sys.databases d
LEFT OUTER JOIN
msdb.dbo.[restorehistory] r ON r.[destination_database_name] = d.NAME)
SELECT
l.[ServerName],
l.[DatabaseName],
l.[RestoreDateTime],
MAX(r.LogDate) AS LogDate,
CONVERT(VARCHAR, MAX(r.LogDate), 100) AS FormattedLogDate
FROM
[LastRestores] l
JOIN
RestoreDate r
ON l.DatabaseName = r.DbName
WHERE
l.[RowNum] = 1
AND l.DatabaseName NOT IN ('master', 'model', 'msdb', 'tempdb')
AND CONVERT(VARCHAR(12), [RestoreDateTime]) = CONVERT(VARCHAR(12), GETDATE())
GROUP BY
l.[ServerName],
l.[DatabaseName],
l.[RestoreDateTime];
DROP TABLE #t;
IF NOT EXISTS (SELECT TOP 1 CityName FROM dbo.City WHERE [Name] = 'Default City')
BEGIN
INSERT dbo.City ( CityName, Status,CityCategoryId) VALUES
(N'Default City', 0, (SELECT CityCategoryId FROM dbo.CityCategory WHERE [CityCategoryName] = N'Default City Category'))
END
GO
i have the the above query which runs fine in SQL server 2012 but fails in SQL Server 2005 with the below error message.
Subqueries are not allowed in this context. Only scalar expressions are allowed.
Change your insert like this.
INSERT dbo.City
(CityName,Status,CityCategoryId)
SELECT N'Default City',0,CityCategoryId
FROM dbo.CityCategory
WHERE [CityCategoryName] = N'Default City Category'
Try using variable #CityCategoryId. I don't know the type of #CityCategoryId. You can use datatype that you want.
IF NOT EXISTS (SELECT TOP 1 CityName FROM dbo.City WHERE [Name] = 'Default City')
BEGIN
Declare #CityCategoryId AS NVARCHAR(100)
SELECT #CityCategoryId = CityCategoryId FROM dbo.CityCategory
WHERE [CityCategoryName] = N'Default City Category'
INSERT dbo.City( CityName, Status, CityCategoryId)
VALUES
(N'Default City', 0, #CityCategoryId)
END
GO
Try like this. Am not sure...
IF NOT EXISTS (SELECT TOP 1 CityName FROM dbo.City WHERE [Name] = 'Default City')
BEGIN
INSERT dbo.City ( CityName, Status,CityCategoryId)
SELECT 'Default City',0, CityCategoryId FROM dbo.CityCategory WHERE [CityCategoryName] = N'Default City Category'
END
GO