Inner Join with order by and where clase - sql

I have created a stored procedure for filling a drop down. But the order by clause not working on my procedure.
ALTER PROCEDURE proc
-- Add the parameters for the stored procedure here
#compID bigint,
#after datetime
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
CREATE TABLE #tmpAuc ( ProjectID BIGINT, Title VARCHAR(256))
INSERT INTO #tmpAuc
SELECT SA.ID ProjectID, SA.Title
FROM [dbo].[Sessions] S
INNER JOIN Auc SA ON S.AucID = SA.ID
WHERE S.Session < 3 AND SA.Status > 0 AND SA.CompanyID = #companyID AND S.LiveBeginDate > #after
ORDER BY LiveBeginDate
SELECT DISTINCT * FROM #tmpAuc
END
I would like to order by descending order of LiveBehinDate

Include the LiveBeginDate in the temp table and from the temp table result ORDER BY LiveBeginDate
CREATE TABLE #tmpAuctions (ProjectID BIGINT, Title VARCHAR(256), LiveBeginDate DATETIME)
INSERT INTO #tmpAuctions (ProjectID, Title, LiveBeginDate)
SELECT SA.ID AS ProjectID, SA.Title, S.LiveBeginDate
FROM [dbo].[Sessions] S
INNER JOIN [Spectrum_Auctions].[dbo].[Auctions] SA ON S.AuctionID = SA.ID
WHERE S.SessionState < 3 AND SA.Status > 0 AND SA.CompanyID = #companyID AND S.LiveBeginDate > #after
SELECT DISTINCT *
FROM #tmpAuctions
ORDER BY LiveBeginDate
or avoid temp table and directly use the SELECT with JOIN inside the procedure:
SELECT SA.ID AS ProjectID, SA.Title
FROM [dbo].[Sessions] S
INNER JOIN [Spectrum_Auctions].[dbo].[Auctions] SA ON S.AuctionID = SA.ID
WHERE S.SessionState < 3 AND SA.Status > 0 AND SA.CompanyID = #companyID AND S.LiveBeginDate > #after
ORDER BY S.LiveBeginDate

That’s because your data is ordered when writing to the temp table that resides in temp dB. Reading from temp dB is never guaranteed to be in order. So when you select star from your temp table that’s what you get.
Get rid of the temp table and do the select directly. This will be faster and more efficient as well. If your proc becomes more complex, use CTEs instead of temp tables as they are easier to conceptualize and run much faster in all cases.

Related

Best way to join this into a temp table and inner join

Just wondering the best way to put this into a temp table and then join it.
IF EXISTS(SELECT LocId
FROM dbo.Locations WITH (NOLOCK)
WHERE SourceSystem = #SourceSystem
AND LocId IN (SELECT ListVal
FROM etopsuser.fnParseListToTable(#LocIdList, ';')) AND IsHot = 1)
BEGIN
Specifically trying to do it on this line of code
(SELECT ListVal
FROM etopsuser.fnParseListToTable(#LocIdList, ';')) AND IsHot = 1)
The NOLOCK is unrelated
You would create a temporary table just like any other table from a select:
SELECT ListVal
INTO #templist
FROM etopsuser.fnParseListToTable(#LocIdList, ';');
Then you would use it as:
SELECT l.LocId
FROM dbo.Locations l JOIN
#templist tl
ON l.LocId = tl.Listval
WHERE l.SourceSystem = #SourceSystem AND l.IsHot = 1
The best way to pass a list into a procedure is to use a Table Valued Parameter
CREATE TYPE dbo.List AS TABLE (ListVal varchar(255));
IF EXISTS(SELECT 1
FROM dbo.Locations l
WHERE l.SourceSystem = #SourceSystem
AND l.LocId IN (
SELECT ll.ListVal
FROM #LocIdList ll
) AND IsHot = 1)
Notes: Always use table references on every column, especially if subqueries are involved. Never use NOLOCK unless you are prepared for incorrect results. EXISTS ignores its SELECT, so SELECT 1 or SELECT NULL is standard.
Then you can pass in the table variable either from client code depending on language, or in T-SQL like this
DECLARE #list dbo.List;
INSERT #list (ListVal)
VALUES ('SomeValue');
EXEC YourProc #LocIdList = #list;

A nested INSERT, UPDATE, DELETE, or MERGE statement must have an OUTPUT clause in UPDATE

I'm trying to update some values based on every Id in the list. The logic I have seems to be what I want.
I want to populate a temporary table of Ids. Then for every ID I want to apply this query and output the deleted date and the ID into a new table I've created.
I keep getting the error:
Msg 10716, Level 15, State 1, Line 25
A nested INSERT, UPDATE, DELETE, or MERGE statement must have an OUTPUT clause.
What does this mean? I thought I am OUTPUTTING into the new table I've created.
USE datatemp
GO
DECLARE #idlist TABLE (id INT)
INSERT INTO #idlist (id) VALUES (3009099)
DECLARE #EndDate DATETIME
SET #EndDate = '2099-12-12'
IF NOT EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'TEMP_TABLE')
BEGIN
CREATE TABLE [TEMP_TABLE] (
[id] INT,
[thedatetoend] DATETIME);
END
BEGIN TRY
SELECT *
FROM #idlist AS idlist
OUTER APPLY(
UPDATE [custprofile]
SET thedatetoend = #EndDate
OUTPUT idlist.id, DELETED.thedatetoend
INTO [TEMP_TABLE]
FROM [custprofile] as bc
INNER JOIN [custinformation] as cc
ON cc.custengageid = bc.custengageid
WHERE cc.id = idlist.id
AND bc.modifierid = 2
AND bc.thedatetoend > GETDATE()
AND cc.type = 1) o
I think you may have more success by using a CTE and avoiding the outer apply approach you are currently using. Updates made to the CTE cascade to the source table. It might look something like the following but as some columns don't reference the table aliases don't expect this to work "as is" (i.e. I'm not sure if you are outputting ccid or bcid and I don't know which table thedatetoend belongs to.)
WITH
CTE AS (
SELECT
cc.id AS ccid, bcid AS bcid, thedatetoend
FROM [custprofile] AS bc
INNER JOIN [custinformation] AS cc ON cc.custengageid = bc.custengageid
INNER JOIN #idlist AS idlist ON cc.id = idlist.id
WHERE bc.modifierid = 2
AND bc.thedatetoend > GETDATE()
AND cc.type = 1
)
UPDATE CTE
SET thedatetoend = #EndDate
OUTPUT ccid, DELETED.thedatetoend
INTO [TEMP_TABLE]

How to create procedure with multiple string select query in sql?

I want to create procedure with multiple string select query.I want to insert data to table variable and join that temp table with other table.
I don't want to create temp table as real tables. I want to insert data to memory temp table.
Here is my procedure,
CREATE PROCEDURE sp_TempBatch
AS
DECLARE #TempBatchSerial TABLE
(
ID int,
Name nvarchar(200),
StockType nvarchar(50),
ItemNo nvarchar(50)
)
DECLARE #TempQuery as nvarchar(MAX)='',
#VendorQuery as nvarchar(MAX)=''
BEGIN
SET #TempQuery='SELECT ID,Name,'
IF StockType = '1'
BEGIN
SET #TempQuery += ' ''Batch'' as StockType,'
END
ELSE
BEGIN
SET #TempQuery += ' ''Serial'' as StockType,'
END
SET #TempQuery += 'ItemNo INTO #TempBatchSerial
FROM Stock'
EXEC (#TempQuery)
SET #VendorQuery+=' SELECT #TempBatchSerial.* FROM #TempBatchSerial
INNER JOIN Vendor
ON #TempBatchSerial.ID = Vendor.ID
INNER JOIN Partner
ON Vendor.parentid = Partner.syskey'
EXEC (#VendorQuery)
END
When execute procedure show error message of Must declare the table variable "#TempBatchSerial"
You have to refer to #tempBatchSerial via an Alias
That's the only way #tempTables can be referred or linked to.
SELECT T.* FROM #TempBatchSerial T
INNER JOIN Vendor
ON T.ID = Vendor.ID
INNER JOIN Partner
ON Vendor.parentid = Partner.syskey
If that doesn't work you can try to put the #tempTable in the #vendorQuery text.

How to declare an array in SQL server query and how to assign value into this array from other select query

ALTER PROCEDURE [dbo].[createTimeFrameReport]
AS
--BEGIN TRAN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
--declare #currentYear varchar (4)
--declare #currentMonth varchar(3)
--declare #currentDay varchar(3)
DECLARE #applicationNo varchar(20);
TYPE ListofIDs IS VARRAY(100) OF NUMBER;
//how to assign value for below code a.APPLICATION_ID into an array
SELECT #ListofIDs =a.APPLICATION_ID from BPM_PROCESS_INSTANCE a,BPM_TASK_INSTANCE b,BPM_PROCESS c where b.PROCESS_INSTANCE_ID=a.ID and c.ID=a.TYPE_ID and a.TYPE_ID=42
AND b.ASSIGNED_ROLE IN('IDB_Reviewer','IFP_TechReviewerPermitting','IFP_ProcessManager','IFP_TechReviewerAssessment')
select #ListofIDs
In SQL there is not Array variable, however some SQL features replaces the logic of that array, it depend on how you use it, and i think what you are looking for is Temporary Tables
how to create temporary tables ? , to create temp table you need to have a hashtag sign # before the name of the temp table. see sample below (2 ways to create temp table
Using CREATE TABLE
CREATE TABLE #testTempTable
(
Column1 DataType,
Column2 DataType,
Column3 DataType,
etc...
)
Using SELECT INTO #testTempTable
SELECT Column1, Column2, Column3
INTO #testTempTable
FROM SourceTableNameHere
There is also called Variable Table in SQL , you can google it to know how to use it.
NOTE: it is best practice to drop the temporary table at the end of the script to avoid errors when the script contains temp table runs in the 2nd time.
sytanx:
DROP TABLE #testTempTable
Hope it helps.
SQL Server has not array type but you can use table variables or temp tables instead.
Also please don't use outdated comma syntax, use JOIN ON instead.
TEMP TABLE:
SELECT a.APPLICATION_ID
INTO #ListofIDs
FROM BPM_PROCESS_INSTANCE a
JOIN BPM_TASK_INSTANCE b
ON b.PROCESS_INSTANCE_ID = a.ID
JOIN BPM_PROCESS c
ON c.ID = a.TYPE_ID
WHERE a.TYPE_ID = 42
AND b.ASSIGNED_ROLE IN('IDB_Reviewer',
'IFP_TechReviewerPermitting',
'IFP_ProcessManager',
'IFP_TechReviewerAssessment');
SELECT #ListofIDs;
TABLE VARIABLE:
DECLARE #ListofIDs TABLE
(
APPLICATION_ID int
);
INSERT INTO #ListofIDs(APPLICATION_ID)
SELECT a.APPLICATION_ID
FROM BPM_PROCESS_INSTANCE a
JOIN BPM_TASK_INSTANCE b
ON b.PROCESS_INSTANCE_ID = a.ID
JOIN BPM_PROCESS c
ON c.ID = a.TYPE_ID
WHERE a.TYPE_ID = 42
AND b.ASSIGNED_ROLE IN('IDB_Reviewer',
'IFP_TechReviewerPermitting',
'IFP_ProcessManager',
'IFP_TechReviewerAssessment');
SELECT #ListofIDs;

What part of this short SQL script run on a production is not optimal?

I am running a script on our production database reffering two tables : our table of users (3700 of them) and the table of quotes that they have made (280000 of them). Quote is the main object in our application, a very large object, for whom many data tables are created and filled. My goal is to clean database from all quotes but those made of a small group of users.
I first create a temp table containing ids of those users (it is used else in the script also) and then a cursor that runs through the main table for the quotes, where they are listed, and for those quotes created from the user group does the necessary cleansing.
I see that this script is going to be executed for 26 hours approximately, which I consider peculiar since I need about 15 minutes for the database restoring in general, and I guess the heaviest sql is executed there. The db, though, weighs more than 100GB.
Is there some part of the script that I am making terribly non-optimal, or you have some suggestion how this could be done with much shorter execution.
We are running SQL Server 2008 R2.
Here's the sketch of the script.
CREATE table #UsersIdsToStay(user_id int)
INSERT INTO #UsersIdsToStay
select user_id
from users
where user_name like '%SOMESTRING '
-----
declare #QuoteId int
declare #UserId int
declare QuoteCursor cursor for
select DISTINCT QuoteId, UserId
from QuotesTable
where UserId not in
(
select * from #UsersIdsToStay
)
open QuoteCursor
while 1=1
begin
fetch QuoteCursor into #QuoteId, #UserId
if ##fetch_status != 0 break
-- all the deletions from related tables are executed here using #QuoteId and #UserId
exec('delete from QuoteHistory where QuoteId = ' + #QuoteId + ' and UserId = ' + #UserId )
exec('delete from QuoteRevisions where QuoteId = ' + #QuoteId + ' and UserId = ' + #UserId )
exec('delete from QuoteItems where QuoteId = ' + #QuoteId + ' and UserId = ' + #UserId )
....
end
close QuoteCursor;
deallocate QuoteCursor
The cursor restricts you to only delete a single User_Id/Quote_Id combination at a time on each related table. By using joins you will be able to delete in mass.
You could also switch out the temp table with a Common Table Expression(CTE). If this is a one off script the temp table should be ok, but for production code I would create a CTE.
if OBJECT_ID('tempdb..#quotesToDelete') is not null
drop table #quotesToDelete
select distinct
ut.user_id,
qt.quote_id
into #quotesToDelete
from dbo.QuotesTable qt (nolock)
inner join dbo.UsersTable ut (nolock)
on qt.user_id = ut.user_id
where ut.user_name not like '%SOMESTRING '
-- all the deletions from related tables are executed here using #QuoteId and #UserId
-- relatedtableA
delete a
from relatedtableA a
inner join #quotesToDelete b
on a.user_id = b.user_id
and a.quote_id = b.quote_id
-- relatedtableB
...
Since you don't show the deletes cannot show you how to avoid a cursor.
But could do this without a temp pretty easy
select DISTINCT QuoteId, UserId
from QuotesTable
where UserId not in
(
select user_id
from users
where user_name like '%SOMESTRING '
)
or
select DISTINCT QuoteId, UserId
from QuotesTable
left join UserId
on UserId.user_id = QuotesTable.UserId
and user_name like '%SOMESTRING '
where UserId.user_id is null
The problem is the cusor and you don't need it
CREATE table #QuotesToDelete(QuoteId int, UserID int)
insert into #QuotesToDelete
select DISTINCT QuoteId, UserId
from QuotesTable
left join UserId
on UserId.user_id = QuotesTable.UserId
and user_name like '%SOMESTRING '
where UserId.user_id is null
delete QH
from QuoteHistory QH
join #QuotesToDelete
on #QuotesToDelete.QuoteId = QH.QuoteId
and #QuotesToDelete.UserID = QH.UserID
delete QR
from QuoteRevisions QR
join #QuotesToDelete
on #QuotesToDelete.QuoteId = QR.QuoteId
and #QuotesToDelete.UserID = QR.UserID