How to get rid of Cursor and use UPDATE with SELECT - sql

I believe that the cursor used in this code is the reason for some major performance issues, however I am new to TSQL.
Following script runs on SQL SERVER 2008. I am trying to redo it so I use JOIN statements instead, however I have not been able to do so successfully.
DECLARE AIRAMSDET CURSOR FOR
SELECT BILL, RECIEPT, NAME
FROM Client_Table
WHERE IsProcessed = 1
AND TYPE IN ('Sub','First_Time','Old') AND LEN(BILL) > 1
OPEN AIRAMSDET
FETCH AIRAMSDET into #VARBILL, #VARRECIEPT, #VARNAME
WHILE ##Fetch_Status = 0
BEGIN
UPDATE archieve
SET entry = left(#VARBILL + '- '+ #VARNAME)
WHERE archiveID = #VARBILL
END

It should be something like following
UPDATE ARCHIEVE
SET ENTRY = CT.BILL + '-' + CT.NAME
FROM CLIENT_TABLE CT
WHERE
ARCHIEVE.ARCHIVEID = CT.BILL
AND CT.ISPROCESSED = 1
AND CT.TYPE IN ('Sub','First_Time','Old') AND LEN(BILL) > 1
I have not included LEFT() as its use in your query wasn't very clear. Left takes an integer_expression as its second parameter while you are passing ##VARNAME which most likely is a VARCHAR. Please add that as you deem fit.

Related

Can Multiple Parameter be used with LIKE in SQL

I am getting data from database in a format like "chem*,bio*" what i want to do is after i split the string into two i want to fetch all records containing "chem" and "bio" .. using LIKE with multiple parameter is something i want since CONTAIN will bring in irrelevant data too. Kindly help.
its something like this
assume:
#cwork2 ='chem*,bio*'
#cw1=#cw1 +'OR contains (name,'''+#Cwork1+''')'
#cw1=#cw1 +'OR name LIKE ('''+#Cwork1+''','%')'
Try this:
You can use pipeline (|) to achieve Or Condition
select * from Tablename where name like '[chem|bio]%';
just add them in an OR condition.
#cw1 = #cw1 OR name like '%chem%' OR name like '%bio%'
i found another way... although he answers provided are right on track but when talking about variables we cannot simply add on variables in the code. Hence forth i decided to put the variable in a #temp table, loop it through and then accordingly fetch data
insert into #publication select item from fsplit(#Work,',')
Declare #loopc int=1
while (#loopc <= (SELECT count(*) from #pub))
Begin
set #Cwork1= (select name from #pub where id= #loopc);
if CHARINDEX(#Cwork1,'*')<0
Begin
set #cw1='or pub.name ='''+#Cwork1+''')'
end
else
begin
set #Cwork1 = REPLACE(#Cwork1,'*','%');
set #cw1=#cw1 +'OR pub.name LIKE ('''+#Cwork1+''')'
end
set #loopc= #loopc +1;
end
set #cw1= (SELECT STUFF(#cw1, CHARINDEX('or', #cw1), LEN('or'), ''))
set #cw1= '('+#cw1+')'
set #Au2= #Au2 + ' and '+ #cw1

Extracting a portion of a value out of a database column using SQL server

I'm trying to extract a portion of a value out of a database column using SQL server.
The example below works in a simple context with a varchar field. The result is: &kickstart& which is what I want.
I now want to do the same when retrieving a column from the database.
But SQL does not like what I am doing. I'm thinking it is something easy that I am not seeing.
Declare #FileName varchar(20) = '&kickstart&.cfg'
Declare #StartPos integer = 0
Declare #FileNameNoExt varchar(20)
SELECT #FileNameNoExt = Left(#FileName,( (charindex('.', #FileName, 0)) - 1))
SELECT #FileNameNoExt
Here is the SQL statement that I can't seem to get to work for me:
Declare #FileNameNoExt as varchar(20)
SELECT
i.InstallFileType AS InstallFileType,
o.OSlabel AS OSLabel,
SELECT #FileNameNoExt = (LEFT(oi.FIleName,( (charindex('.', oi.FIleName, 0) ) - 1) )) AS FileNameNoExt,
oi.FIleName AS FIleName
FROM
dbo.OperatingSystemInstallFiles oi
JOIN dbo.InstallFileTypes i ON oi.InstallFileTypeId = i.InstallFileTypeId
JOIN dbo.OperatingSystems o ON oi.OperatingSystemId = o.OperatingSystemId
Why do you need the variable at all? What's wrong with:
SELECT
i.InstallFileType AS InstallFileType,
o.OSlabel AS OSLabel,
LEFT(oi.FIleName,( (charindex('.', oi.FIleName, 0) ) - 1) ) AS FileNameNoExt,
oi.FIleName AS FIleName
FROM
dbo.OperatingSystemInstallFiles oi
JOIN dbo.InstallFileTypes i ON oi.InstallFileTypeId = i.InstallFileTypeId
JOIN dbo.OperatingSystems o ON oi.OperatingSystemId = o.OperatingSystemId
You've put a SELECT inside another SELECT list without nesting, which is a syntax error in SQL Server.
You are also attempting to assign a variable while performing a data-retrieval operation. You can select all data to be shown, or all data into variables but not both at the same time.
When the two issues above are resolved, I think you may still run into issues when committing filenames into a variable which only allows 20 characters - but then I don't know anything about your dataset.

Set Date from another table in SQL Server

I have a code in VB.Net application which I would like to move to stored procedure.
VB code looks something like this :
if(id == 3)
{
var year = Year(invoiceDate)
updatedDate = DateSerial(dueYear, DueDateMonth, DueDateDay)
If updatedDate < invoiceDate Then
updatedDate += 1
updatedDate = DateSerial(updatedDate , getMonthFromDBTable, getDayFromDBTable)
End If
}
This is part of a condition which I am trying to resolve.
Currently in SQL I have the following
DECLARE #tmpCalendarDate DATETIME;
DECLARE #tmpYear int;
SET #tmpCalendarDate = convert(varchar(10), getdate(),120);
SET #tmpYear = DATEPART(yyyy, #tmpCalendarDate);
SELECT COALESCE (
CASE WHEN tt.ID = 1 THEN DATEADD(day, t.DaysUntilDue, r.InvoiceDate) END,
CASE WHEN tt.ID = 3 THEN -- This is where I need to add the condition.
I was thinking of setting the #tmpCalendarDate with the values to look something like
CASE WHEN tt.ID = 3 THEN #tmpCalendarDate = '#tmpYear-t.DueDateMonth-t.DueDateDay'
where t is a table.
This value cannot be changed, so I would rather calculate and fetch it once rather than calculating it every time binding changes (wpf application).
Any help is greatly appreciated.
UPDATE: I realized maybe I am vague with my question, so here it is
How do i set #tmpCalendarDate? I tried
SELECT #tmpCalendarDate = '#tmpYear-t.DueDateMonth-t.DueDateDay' FROM table t
and I get an error 'Conversion failed when converting date and/or time from character string.' Instead I am expecting something like #tmpCalendarDate to be set to '2016-03-12'
Also, can I add an If..Else condition inside CASE.Then
In my example:
CASE WHEN tt.ID = 3 THEN #tmpCalendarDate = '#tmpYear-t.DueDateMonth-t.DueDateDay'
IF (#tmpCalendarDate > InvoiceDate)
BEGIN
--Do some logic
END
ELSE
--Do some logic
BEGIN
END
You can use DATEFROMPARTS
#tmpCalendarDate = DATEFROMPARTS(#tmpyear, t.DueDateMonth, t.DueDateDay)
Your mistake in your original attempt is you are setting #tempCalendarDate to actual string #tmpYear-t.DueDateMonth-t.DueDateDay which results in a conversion error.

SQL Query Optimization taking 20 - 30 secs to run

Below query takes 20 secs to execute and i need to optimize it as much as i can. Please help me on this.
SELECT Distinct
qh.QuoteHeaderId, [dbo].[mpx2_Get_PhoneGrade](qh.QuoteHeaderId)
FROM
t_QuoteHeader QH
INNER JOIN
t_HandsetQuote h ON Qh.QuoteHeaderId = h.QuoteHeaderId
INNER JOIN
t_phoneAudit P ON ISNULL(h.InspectionPhoneAuditId, h.QuotePhoneAuditId) = p.PhoneAuditId
INNER JOIN
mpx2_vw_customers C ON qh.CustomerId = C.CustomerId
INNER JOIN
#ContactChannels CC ON C.ContactChannelId = CC.ContactChannelId
LEFT OUTER JOIN
t_HandsetQuoteAdditionalInfo_TRNX hqa ON hqa.hqid = h.HandsetQuoteId
WHERE
((#VirtualStatusId = 0 OR #VirtualStatusId = -2 OR
C.ContactChannelId NOT IN (1, 2, 13, 80)))
AND ((#VirtualStatusId = -2) OR
('Q'+ CAST(Qh.QuoteStatusId AS VARCHAR(3)) + 'S' + CAST(h.StockStatusId AS VARCHAR(3)) IN
(SELECT 'Q'+ CAST(QuoteStatusId AS VARCHAR(3)) + 'S' + CAST(StockStatusId AS VARCHAR(3)) FROM t_VirtualStatusMap WHERE (#VirtualStatusId IS NULL OR #VirtualStatusId IN (0,-1) OR VirtualStatusId = #VirtualStatusId))
)
)
AND ((qh.IsCancelled = 0 and #onlyOpenOrders = 1) OR #onlyOpenOrders = 0)
AND ((h.IsCancelled = 0 and #onlyOpenOrders = 1) OR #onlyOpenOrders = 0)
AND (qh.ConfirmedDate <= #CutOff)
Please help me to optimize it. This query is used in a stored procedure.
This is too long for a comment.
ORs in WHERE and ON clauses are very hard to optimize. Often with a query like this, it is better to construct the query based on the components and use dynamic SQL.
For instance, the condition on #OnlyOpenOrders would be included like this:
declare #sql varchar(max);
set #sql = ' . . .';
declare #where varchar(max);
set #where = 'where . . .';
if (#OnlyOpenOrders = 0) begin
set #where = #where + ' and qh.IsCancelled = 0 and h.IsCancelled = 0'
end;
set #sql = #sql + ' ' + #where;
exec sp_executesql #sql;
You need to have similar logic for all the variables you are using.
There are a couple of things, although as others have said without all the required information such as a full execution plan, and schemas of the tables involved it is mostly guidelines/guesswork;
1.) In this part, it would appear you build a string from QuoteStatusId and StockStatusId in order to compare them;
('Q'+ CAST(Qh.QuoteStatusId AS VARCHAR(3)) + 'S' + CAST(h.StockStatusId AS VARCHAR(3))
IN
(SELECT 'Q'+ CAST(QuoteStatusId AS VARCHAR(3)) + 'S' + CAST(StockStatusId AS VARCHAR(3))
FROM t_VirtualStatusMap
WHERE (#VirtualStatusId IS NULL
OR #VirtualStatusId IN (0,-1) OR VirtualStatusId = #VirtualStatusId)))
If you skipped building the strings, since they are comprised of the same two columns and just compared the two columns directly that may speed things up.
2.) Have you tried adding the index which it suggests in the picture you attached? Without seeing your schema and an execution plan it is hard to suggest appropriate ones but it might be worth adding the one suggested (right click the green writing and it will generate the code to add the suggested index). I would read up on indexes and ensure there is an appropriate index for the query to use. ConfirmedDate seems like an obvious one, as well as all the join keys.
3.) As Gordon suggested using dynamic sql or if you are not comfortable with that - maybe splitting the query out into a few queries and switching between each using an IF statement, could help SQL generate a good plan for each scenario, instead of trying to find a generic plan to work for all cases.

Stored procedure to find next and previous row in SQL Server 2005

Right now I have this code to find next and previous rows using SQL Server 2005. intID is the gallery id number using bigint data type:
SQL = "SELECT TOP 1 max(p.galleryID) as previousrec, min(n.galleryID) AS nextrec FROM gallery AS p CROSS JOIN gallery AS n where p.galleryid < '"&intID&"' and n.galleryid > '"&intID&"'"
Set rsRec = Server.CreateObject("ADODB.Recordset")
rsRec.Open sql, Conn
strNext = rsRec("nextrec")
strPrevious = rsRec("previousrec")
rsRec.close
set rsRec = nothing
Problem Number 1:
The newest row will return nulls on the 'next record' because there is none. The oldest row will return nulls because there isn't a 'previous record'. So if either the 'next record' or 'previous record' doesn't exist then it returns nulls for both.
Problem Number 2:
I want to create a stored procedure to call from the DB so intid can just be passed to it
TIA
This will yield NULL for previous on the first row, and NULL for next on the last row. Though your ordering seems backwards to me; why is "next" lower than "previous"?
CREATE PROCEDURE dbo.GetGalleryBookends
#GalleryID INT
AS
BEGIN
SET NOCOUNT ON;
;WITH n AS
(
SELECT galleryID, rn = ROW_NUMBER()
OVER (ORDER BY galleryID)
FROM dbo.gallery
)
SELECT
previousrec = MAX(nA.galleryID),
nextrec = MIN(nB.galleryID)
FROM n
LEFT OUTER JOIN n AS nA
ON nA.rn = n.rn - 1
LEFT OUTER JOIN n AS nB
ON nB.rn = n.rn + 1
WHERE n.galleryID = #galleryID;
END
GO
Also, it doesn't make sense to want an empty string instead of NULL. Your ASP code can deal with NULL values just fine, otherwise you'd have to convert the resulting integers to strings every time. If you really want this you can say:
previousrec = COALESCE(CONVERT(VARCHAR(12), MIN(nA.galleryID)), ''),
nextrec = COALESCE(CONVERT(VARCHAR(12), MAX(nB.galleryID)), '')
But this will no longer work well when you move from ASP to ASP.NET because types are much more explicit. Much better to just have the application code be able to deal with, instead of being afraid of, NULL values.
This seems like a lot of work to get the previous and next ID, without retrieving any information about the current ID. Are you implementing paging? If so I highly recommend reviewing this article and this follow-up conversation.
Try this (nb not tested)
SELECT TOP 1 max(p.galleryID) as previousrec, min(n.galleryID) AS nextrec
FROM gallery AS p
CROSS JOIN gallery AS n
where (p.galleryid < #intID or p.galleryid is null)
and (n.galleryid > #intID or n.galleryid is null)
I'm assuming you validate that intID is an integer before using this code.
As for a stored procedure -- are you asking how to write a stored procedure? If so there are many tutorials which are quite good on the web.
Since Hogan contributed with the SQL statement, let me contribute with the stored proc part:
CREATE PROCEDURE spGetNextAndPreviousRecords
-- Add the parameters for the stored procedure here
#intID int
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
SELECT TOP 1 max(p.galleryID) as previousrec, min(n.galleryID) AS nextrec
FROM gallery AS p
CROSS JOIN gallery AS n
where (p.galleryid < #intID or p.galleryid is null)
and (n.galleryid > #intID or n.galleryid is null)
END
And you call this from code as follows (assuming VB.NET):
Using c As New SqlConnection(ConfigurationManager.ConnectionStrings("ConnectionString").ConnectionString)
c.Open()
Dim command = New SqlCommand("spGetNextAndPreviousRecords")
command.Parameters.AddWithValue("#intID", yourID)
Dim reader as SqlDataReader = command.ExecuteReader()
While(reader.Read())
' read the result here
End While
End Using