SQL server stored procedure - Can I invert this query? - sql-server

I am not an sql Guru, that's why I'm asking you guys.
I have this stored procedure:
USE [groep2_festivals]
GO
/****** Object: StoredProcedure [dbo].[GetGroupsNotOfFestival] Script Date: 15-05-13 10:03:17 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author: Robbie Vercammen
-- Create date: 2013-05-15
-- Description: Getting all groups not on a defined festival
-- =============================================
ALTER PROCEDURE [dbo].[GetGroupsNotOfFestival]
#festId nvarchar(4)
AS
BEGIN
SELECT DISTINCT b.*, p.*
FROM bands b
JOIN bandsperfestival bpf ON b.band_id = bpf.band_id
JOIN podia p ON p.pod_id = bpf.pod_id
WHERE bpf.fest_id != #festId
END
And these tables,
Bands:
Podia (Stages in english):
BandsPerFestival holding all bands that perform on festivals:
I used this stored procedure to get all bands performing on a specific festival (by festival id) and that works, but I would like to invert this but simple replacing WHERE bpf.fest_id = #festId with WHERE bpf.fest_id != #festId doesn't seem to work. I get the same list but the bands that actually do perform on a festival are returned twice.
Example:
As you can see, nickelback appears in the list twice when they are actually performing on the chosen festival.
Any help is appreciated.
EDIT: I should have said this earlier, but I want all the bands that are not performing on a specific festival,

Do a left outer join, and then forced the right side of the join to be null.
SELECT DISTINCT b.*
FROM bands b
left outer JOIN bandsperfestival bpf ON b.band_id = bpf.band_id
and #festId = bpf.fest_id
where bpf.fest_id is null

You'll need to explain what you mean when you say "Invert" this. Do you mean you want all bands that did NOT play any festival? Or All bands that did not play a specific festival?

Related

Selection Criteria when running an SP

enter image description hereSo I created a small SP which is working fine, however I would like to be able to make it ask you to select a start and end date when executing it, thus far I have had no joy in working it out.
Below is my query, could someone please advise me what I need to do in order to force you to select both the start and end date when executing?
I have tried a hundred different #set date commands but am not winning (I am not a pro at this but leaning as I go along).
also attached is a screenshot of what I see when executing the SP, there is nothing parameters which is what I am struggling with.
Thanks!
USE [CBS_AFRICA_LIVECOPY]
GO
/****** Object: StoredProcedure [dbo].[usp_LOADINGHOURS] Script Date: 25/01/2019 19:54:41 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[usp_LOADINGHOURS]
AS
SELECT FOLIO_NUMBER, STATUS,  FORMAT(TERM_START_LOAD_TIME ,'HH') as TERM_START_LOAD_TIME, FORMAT(TERM_END_LOAD_TIME ,'HH')
as TERM_END_LOAD_TIME,TERMINAL_NAME, TERMINAL_ID FROM ORDERS
JOIN TERMINAL_OWNER ON ORDERS.LOADING_TERMINAL_ID = TERMINAL_OWNER.TERMINAL_ID
ORDER BY FOLIO_NUMBER DESC
You may want to try this
ALTER PROCEDURE [dbo].[usp_LOADINGHOURS]
#startdate as datetime,
#enddate as datetime
AS
Begin
SELECT FOLIO_NUMBER, STATUS,
FORMAT(TERM_START_LOAD_TIME ,'HH') as
TERM_START_LOAD_TIME,
FORMAT(TERM_END_LOAD_TIME ,'HH') as
TERM_END_LOAD_TIME,
TERMINAL_NAME,
TERMINAL_ID
FROM ORDER JOIN TERMINAL_OWNER ON
ORDERS.LOADING_TERMINAL_ID =
TERMINAL_OWNER.TERMINAL_ID
Where DBTABLE.DATE>=#startdate
AND DBTABLE.DATE<=#enddate
ORDER BY FOLIO_NUMBER DESC
End

Issue with the T-SQL Replace function

I'm currently facing a strange situation.
I'm collecting code of existing stored procedures from a query to a TMP table.
TABLE:
##SPListAndCode
(
Code nVarchar(MAX)
)
Query:
INSERT INTO ##SPListAndCode
SELECT OBJECT_DEFINITION (OBJECT_ID('SPname')))
After that I am trying to replace values to get from Create query, Alter query
REPLACE(CODE, 'CREATE PROCEDURE', 'ALTER PROCEDURE')
But problem is this: REPLACE function is not replacing values.
But, when I am trying to use
REPLACE(CODE, 'CREATE', 'ALTER')
function works as expected.
But this scenario are not acceptable for me, because inside the stored procedure there can be things like
CREATE TABLE
Example data inside "Code" column:
/****** Object: StoredProcedure dbo.spName Script Date: 6/20/2016 9:10:18 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE dbo.spName
AS
DECLARE #pStartDate date, #x int
SET #pStartDate = (SELECT max(CT_ACTIVITY_DATE) FROM Table)
...
Thanks a lot in advance for any kind of support!
Your stored procedure has two spaces between CREATE and PROCEDURE, while your replace is looking for the string with a single space between the words.
To gain access to the actual code contained inside of the stored procedures, you can use something like this:
SELECT
so.name [ObjectName], so.type,
OBJECT_NAME(sc.id), sc.id, sc.colid , sc.[text]
FROM
sys.syscomments sc
INNER JOIN
sys.sysobjects so ON so.id = sc.id
WHERE
so.type = 'P'
ORDER BY
sc.id, sc.colid
Note there can be multiple entries for each object, and the colid is used to order those entries.

Is a Stored Procedure suitable for my task

I am completely new to SQL Server and a bit lost. When I try the following, it executes the first three lines and ignores the rest, just get
'Command(s) completed successfully.'
USE [RenewalsDb]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[One]
AS
BEGIN
SET NOCOUNT ON;
DROP TABLE [dbo].NewTransTable;
SELECT * INTO [dbo].[NewTransTable] FROM [dbo].aqryTransTable;
DELETE FROM [dbo].[NewTransTable] WHERE (((NewTransTable.CURRENT_LICENSE_SKU_DESC) Like '% partner program %'));
DELETE FROM [dbo].[NewTransTable] WHERE (((NewTransTable.RENEWAL_MAINTAINANCE_SKU_DESC) Like '% partner program %'));
UPDATE NewTransTable SET NewTransTable.[Quote Number] = Null;
UPDATE dbo.TransactionTable SET Concat = dbo.qryNamedAcReseller.LATEST_DISTRIBUTOR_NAME + dbo.qryNamedAcReseller.[Sub Territory FY14 ]
FROM dbo.TransactionTable INNER JOIN
dbo.qryNamedAcReseller ON dbo.TransactionTable.LATEST_INSTANCE_NUMBER = dbo.qryNamedAcReseller.LATEST_INSTANCE_NUMBER;
UPDATE dbo.TransactionTable SET Concat = dbo.qryNamedAcReseller.[Sub Territory FY14 ]
FROM dbo.TransactionTable INNER JOIN
dbo.qryNamedAcReseller ON dbo.TransactionTable.LATEST_INSTANCE_NUMBER = dbo.qryNamedAcReseller.LATEST_INSTANCE_NUMBER
WHERE Concat IS NULL;
UPDATE dbo.NewTransTable SET [Quote Number] = dbo.Autogen.[Quote Number] FROM dbo.Autogen RIGHT OUTER JOIN
dbo.NewTransTable ON dbo.Autogen.[IB Reference Num] = dbo.NewTransTable.LATEST_INSTANCE_NUMBER AND
dbo.Autogen.[Quote Known As] = dbo.NewTransTable.[Quote Known As]
DROP TABLE [dbo].NewTransTable2;
SELECT * INTO [dbo].[NewTransTable2] FROM [dbo].aqryTransTable2;
ALTER TABLE [dbo].NewTransTable2 ADD Named_Account nvarchar(255);
END
GO
Welcome to stackoverflow.
Stored Procedure is like a template which can reused multiple times and it can be made dynamic with the help or parameters. Refer mssqltips.com - SQL Server Stored Procedure Tutorial on guide to Stored Procedures. If you want to execute some commands only once, Stored Procedure is not the right thing.
So when you execute the above script, what SQL Server is doing is creating the template structure i.e. Stored procedure named [One] and not actually running the scripts within the stored procedure.
To execute this stored procedure named [One] you have to call it using EXEC One or just simply One and Execute (F5)

Trigger not firing in production but does in non-production

I have a trigger that is firing with out issue in non-production but the same exact code is failing to fire in production. I've confirmed it's not disabled and I've done a trace to see that it is not even executing in production.. I've checked the relevant OBJECTPROPERTY elements and they are the same. I've confirm the code is the same. I've confirmed the same inserts are coming from the application. Below is the code for this trigger:
/******
Object: Trigger [dbo].[tr_trigger_ins]
Script Date: 06/02/2012 16:51:51
******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER OFF
GO
CREATE TRIGGER [dbo].[tr_trigger_ins] ON [dbo].[table_1]
FOR INSERT
AS
BEGIN
UPDATE table_2
SET col_1 =
CASE
WHEN i.col_2 = '0' THEN 0 ELSE 1
END
FROM INSERTED i
INNER JOIN table_3 pa
ON i.col_3 = pa.col_3 AND pa.col_4 = 'ispublic'
INNER JOIN table_4 pp
ON i.col_5 = pp.col_5
INNER JOIN table_2 cs
ON pp.col_6 = cs.col_6
END
GO
Below is a trigger that is an instead of insert on the same table that is executing in both environments:
/******
Object: Trigger [dbo].[tr_trigger_before_ins]
Script Date: 06/02/2012 16:55:52
******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER OFF
GO
CREATE TRIGGER [dbo].[tr_trigger_before_ins] ON [dbo].[table_1]
INSTEAD OF INSERT
AS
BEGIN
INSERT INTO table_1
SELECT * FROM INSERTED
WHERE col_3 in (73, 199)
END
GO
Any help is greatly appreciated.
First make sure the trigger hasn't been disabled:
ENABLE Trigger tr_trigger_ins ON dbo.table_1;
GO
Ultimately it came down to the issue of replication. Transactions flowed over in a different order than expected. Once we accommodated for this in the trigger logic it worked well.

SQL Server proc running 5x slower than plain query

I have the following query:
DECLARE #DaysNotUsed int = 14
DECLARE #DaysNotPhoned int = 7
--Total Unique Students
DECLARE #totalStudents TABLE (SchoolID uniqueidentifier, TotalUniqueStudents int)
INSERT INTO #totalStudents
SELECT
SSGG.School,
COUNT(DISTINCT S.StudentID)
FROM Student S
INNER JOIN StudentStudents_GroupGroups SSGG ON (SSGG.Students = S.StudentID AND SSGG.School = S.School)
INNER JOIN [Group] G ON (G.GroupID = SSGG.Groups AND G.School = SSGG.School)
INNER JOIN SessionHistory SH ON (SH.Student = S.StudentID AND SH.School = S.School AND SH.StartDateTime > GETDATE() - #DaysNotUsed)
WHERE G.IsBuiltIn = 0
AND S.HasStartedProduct = 1
GROUP BY SSGG.School
--Last Used On
DECLARE #lastUsed TABLE (SchoolID uniqueidentifier, LastUsedOn datetime)
INSERT INTO #lastUsed
SELECT
vi.SchoolID,
MAX(sh.StartDateTime)
FROM View_Installation as vi
INNER JOIN SessionHistory as sh on sh.School = vi.SchoolID
GROUP BY vi.SchoolID
SELECT
VI.SchoolID,
INS.DateAdded,
INS.Removed,
INS.DateRemoved,
INS.DateToInclude,
VI.SchoolName AS [School Name],
VI.UsersLicensed AS [Licenses],
ISNULL(TS.TotalUniqueStudents, 0) as [Total Unique Students],
ISNULL(TS.TotalUniqueStudents, 0) * 100 / VI.UsersLicensed as [% of Students Using],
S.State,
LU.LastUsedOn,
DATEDIFF(DAY, LU.LastUsedOn, GETDATE()) AS [Days Not Used],
SI.AreaSalesManager AS [Sales Rep],
SI.CaseNumber AS [Case #],
SI.RenewalDate AS [Renewal Date],
SI.AssignedTo AS [Assigned To],
SI.Notes AS [Notes]
FROM View_Installation VI
INNER JOIN School S ON S.SchoolID = VI.SchoolID
LEFT OUTER JOIN #totalStudents TS on TS.SchoolID = VI.SchoolID
INNER JOIN #lastUsed LU on LU.SchoolID = VI.SchoolID
LEFT OUTER JOIN InactiveReports..SchoolInfo SI ON S.SchoolID = SI.SchoolID
LEFT OUTER JOIN InactiveReports..InactiveSchools INS ON S.SchoolID = INS.SchoolID
WHERE VI.UsersLicensed > 0
AND VI.LastPhoneHome > GETDATE() - #DaysNotPhoned
AND
(
(
SELECT COUNT(DISTINCT S.StudentID)
FROM Student S
INNER JOIN StudentStudents_GroupGroups SSGG ON (SSGG.Students = S.StudentID AND SSGG.School = S.School)
INNER JOIN [Group] G ON (G.GroupID = SSGG.Groups AND G.School = SSGG.School)
WHERE G.IsBuiltIn = 0
AND S.School = VI.SchoolID
) * 100 / VI.UsersLicensed < 50
OR
VI.SchoolID NOT IN
(
SELECT DISTINCT SH1.School
FROM SessionHistory SH1
WHERE SH1.StartDateTime > GETDATE() - #DaysNotUsed
)
)
ORDER BY [Days Not Used] DESC
Running just plain sql like this in SSMS take about 10 seconds to run. When I created a stored procedure with exactly the same code, the query takes 50 seconds instead. The only difference in the actual code of the proc is a SET NOCOUNT ON that the IDE put in by default, but adding that line to the query doesn't have any impact. Any idea what would cause such a dramatic slow down like this?
EDIT I neglected the declare statements at the beginning. These are not in the proc, but are parameters to it. Could this be the difference?
I agree about the potential parameter sniffing issue, but I would also check these settings.
For the procedure:
SELECT uses_ansi_nulls, uses_quoted_identifier
FROM sys.sql_modules
WHERE [object_id] = OBJECT_ID('dbo.procedure_name');
For the SSMS query window where the query is running fast:
SELECT [ansi_nulls], [quoted_identifier]
FROM sys.dm_exec_sessions
WHERE session_id = ##SPID;
If either of these don't match, you might consider dropping the stored procedure and re-creating it with those two settings matching. For example, if the procedure has uses_quoted_identifier = 0 and the session has quoted_identifier = 1, you could try:
DROP PROCEDURE dbo.procedure_name;
GO
SET QUOTED_IDENTIFIER ON;
GO
CREATE PROCEDURE dbo.procedure_name
AS
BEGIN
SET NOCOUNT ON;
...
END
GO
Ideally all of your modules will be created with the exact same QUOTED_IDENTIFIER and ANSI_NULLS settings. It's possible the procedure was created when the settings were off (the default is on for both), or it's possible that where you are executing the query, one or both options are off (you can change this behavior in SSMS under Tools/Options/Query Execution/SQL Server/ANSI).
I'm not going to make any disclaimers about the behavior of the stored procedure with the different settings (for example you may have wanted ANSI_NULLS off so you could compare NULL = NULL), that you'll have to test, but at least you'll be comparing queries that are being run with the same options, and it will help narrow down potential parameter sniffing issues. If you're intentionally using SET ANSI_NULLS OFF, however, I caution you to find other approaches as that behavior will eventually be unsupported.
Other ways around parameter sniffing:
make sure you don't inadvertently compile the procedure with atypical parameters
use the recompile option either on the procedure or on the statement that seems to be the victim (I'm not sure if all of these are valid, because I can only tell that you are using SQL Server 2005 or greater, and some of these were introduced in 2008)
declare local variables similar to your input parameters, and pass the input parameter values to them, using the local variables later in the prodedure and ignoring the input parameters
The last option is my least favorite, but it's the quickest / easiest fix in the midst of troubleshooting and when users are complaining.
Also, in addition to everything else mentioned, if you are on SQL Server 2008 and up, have a look at OPTIMIZE FOR UNKNOWN http://blogs.msdn.com/b/sqlprogrammability/archive/2008/11/26/optimize-for-unknown-a-little-known-sql-server-2008-feature.aspx
I would recommend recompiling the execution plan for the stored procedure.
usage: sp_recompile '[target]'
example: sp_recompile 'dbo.GetObject'
When you execute a query from SSMS the query plan is automatically redone every time its executed. However with stored procs, sql server caches execution plans for stored procedures, and its this execution plan that gets used everytime the stored proc is called.
Link for sp_recompile.
You can also change the proc to use with WITH RECOMPILE clause within the stored proc.
Example:
CREATE PROCEDURE dbo.GetObject
(
#parm1 VARCHAR(20)
)
WITH RECOMPILE
AS
BEGIN
-- Queries/work here.
END
However this will force the execution plan to be recompiled every time the stored proc is called. This is good for dev/testing where the proc and/or data changes quite frequently. Make sure you remove it when you deploy it to production, as this can have a performance hit.
sp_recompile only recompiles the execution plan once. If you need to do it again at a later date, you will need to make the call again.
Good luck!
OK, thank you all for your help. Turns out it was a terribly stupid rookie mistake. The first time I created the proc, it created it under my user's schema instead of the dbo schema. When I called the proc I was simply doing 'exec proc_name', which I'm realizing now was using the version of the proc under my user's schema. Running 'exec dbo.proc_name' ran as expected.

Resources