SQL multiple if statements, same result set, different argument - sql

I am writing a stored proc that calculates a WHOLE bunch of different things, but I have a bit in it, that is repeated about 9 times.
eg:
if #argA = 1 (true)
select Count(samples) from dbo.X where type = #argAType
if #argB = 1 (true)
select Count(samples) from dbo.X where type = #argBType
if #argC = 1
select Count(samples) from dbo.X where type = #argCType
and so on...
how can I write a function (or something similar) that I can pass in a bit (true or false), and other argument, and only return the result set if true???

Is this what you're looking for? This is the best I can deduce based on the question as it's currently posted.
SELECT COUNT(samples)
FROM dbo.X
WHERE
(type=#argAType AND #argA=1)
OR
(type=#argBType AND #argB=1)
OR
(type=#argCType AND #argC=1)
In function form, I think this is right:
CREATE FUNCTION GetCount(#n AS BIGINT) RETURNS BIGINT
AS
BEGIN
DECLARE #count BIGINT
SELECT #count = COUNT(samples)
FROM dbo.X
WHERE
(type=#argAType AND #argA=1)
OR
(type=#argBType AND #argB=1)
OR
(type=#argCType AND #argC=1)
RETURN #count
END

Related

Extract a part of string with complex pattern SQL

I am working with string as below:
DOT LTB TOL SP BLM 3X(35X**25.1**GR)BWY BNL
And I am trying to extract the float between the last X and G -> 25.1.
In Python it is an easy task using regex expression: **[0-9]+X([0-9\.]+)G**
But I could not find a way to extract the data here in SQL Server:
I tried to write a function that define the position of X and the ) argument like that:
AS
Begin
Declare #LastX as INT
Declare #LastG as INT
Declare #Diff as INT
Declare #Result as varchar(50)
Set #LastX = LEN(#Temp) - CAST(CHARINDEX('X', REVERSE(#Temp)) AS Integer)
Set #LastG = LEN(#Temp) - CAST(CHARINDEX(')', REVERSE(#Temp)) AS Integer)
Set #Diff = #LastG - #LastX
IF #Diff > 0
Set #Result = SUBSTRING(#Temp, #LastX, #Diff)
ELSE
Set #Result = 0
Return #Result
End
My result is 5X25.1G
Can you help me with this?
I'm also open if you have other suggestion to extract this value in SQL.
If it's always between the last X and last G, you could use a couple of CHARINDEX's as you have tried. I prefer to do this in the FROM and use APPLY to avoid repetition of code and a "nasty" long single expression:
SELECT *,REVERSE(SUBSTRING(R.YourString,CI1.I+1,CI2.I-CI1.I-1))
FROM (VALUES('DOT LTB TOL SP BLM 3X(35X25.1GR)BWY BNL'))V(YourString)
CROSS APPLY(VALUES(REVERSE(V.YourString)))R(YourString)
CROSS APPLY(VALUES(NULLIF(CHARINDEX('G',R.YourString),0)))CI1(I)
CROSS APPLY(VALUES(NULLIF(CHARINDEX('X',R.YourString,CI1.I),0)))CI2(I)
That really long expression would be the following, by the way:
SELECT V.Yourstring,
REVERSE(SUBSTRING(REVERSE(V.YourString),NULLIF(CHARINDEX('G',REVERSE(V.YourString)),0)+1,NULLIF(CHARINDEX('X',REVERSE(V.YourString),NULLIF(CHARINDEX('G',REVERSE(V.YourString)),0)),0)-NULLIF(CHARINDEX('G',REVERSE(V.YourString)),0)-1))
FROM (VALUES('DOT LTB TOL SP BLM 3X(35X25.1GR)BWY BNL'))V(YourString)
Have fun trying to read that. Hence why the APPLYs. 🙃

SQL : Update value when the value in the database is null

I know this is already asked question and possible to be close.
But i really want a answer, I already searched through the internet, Read documentations, Blogs, and Question to SO.
This is my Query so Far,
declare #count numeric
select #count = (select count(1) from E496_TitleReference a where
exists (select 1 from #tempTransactions b where a.EPEB_RoD = b.tEPEB_RoD and
a.EPEB_ENO = b.tEPEB_ENO and a.EPEB_ID = b.tEPEB_ID and a.Title_Seq = b.tTitle_Seq))
update E496_TitleReference
set PrintStatus = '{0}',Is_AESM=isnull(-1,Is_AESM)
from E496_TitleReference a where
exists (select 1 from #tempTransactions b where a.EPEB_RoD = b.tEPEB_RoD and
a.EPEB_ENO = b.tEPEB_ENO and a.EPEB_ID = b.tEPEB_ID and a.Title_Seq = b.tTitle_Seq)
if ##rowcount <> #count
begin
rollback tran
Print "Error: There is an error on table E496_TitleReference."
return
end
go
For eg, In my table in Database i have column name Is_AESM, In Is_AESM column it have 4 values.
Is_AESM
NULL
NULL
-1
-2
Something like this.
Now when i run my script, it has no problem when i run it,
Is_AESM=isnull(-1,Is_AESM)
In this query it will detect if Is_AESM is null, it will update Is_AESM = -1 if not it will retain the value.
Now my problem is, if my query detect Is_AESM has a null value, it will update all the value to -1.
Is_AESM
-1
-1
-1
-1
The result is something like that. Now i want is update only the null value not all the value in column Is_AESM.
I think this query is wrong Is_AESM=isnull(-1,Is_AESM).
Any ideas will be a big help.
You may try with coalsece() function
update E496_TitleReference
set PrintStatus = '{0}',Is_AESM=coalsece(Is_AESM,-1)
from E496_TitleReference a where
exists (select 1 from #tempTransactions b where a.EPEB_RoD = b.tEPEB_RoD and
a.EPEB_ENO = b.tEPEB_ENO and a.EPEB_ID = b.tEPEB_ID and a.Title_Seq = b.tTitle_Seq)
you need to replace order of parameters.
Is_AESM=isnull(Is_AESM, -1)
You can use COALSECE function. It returns the first non-null entry from the given list. So:
Is_AESM= COALSECE(IS_AESM,-1)
This will return IS_AESM value if it is not null (since it is the first non-null value)
Else if IS_AESM is NULL then it returns -1 (since it is the non-null value)

SQL Where with Binary(n) column

I have a stored procedure:
ALTER PROCEDURE [dbo].[spUpdateOrInsertNotification]
#ContentJsonHash BINARY(32)
AS
DECLARE #NotificationId INT;
SET #NotificationId = (SELECT #NotificationId
FROM dbo.tblNotifications n
WHERE n.ContentJsonHash = #ContentJsonHash);
IF #NotificationId IS NOT NULL
BEGIN
-- Increment Count
END
ELSE
BEGIN
-- Insert new row.
END
It's supposed to check if the Hash already exists and if it does, increment the count for the row, otherwise insert the row. However, it never finds the Hash and the corresponding NotificationId. NotificationId is always null.
If I run it twice, passing it the same data (a C# array byte[32]). It never finds the same NotificationId and I end up with duplicate entries being put in.
e.g.
NotificationId | ContentJsonHash
9 0xB966C33517993003D789EDF78DA20C4C491617F8F42F76F48E572ACF8EDFAC2A
10 0xB966C33517993003D789EDF78DA20C4C491617F8F42F76F48E572ACF8EDFAC2A
Can I not do comparisons on Binary(n) fields like this WHERE n.ContentJsonHash = #ContentJsonhash ?
The C# code:
using (var conn = new SqlConnection(Sql.ConnectionString))
{
await conn.OpenAsync();
using (var cmd = new SqlCommand(Sql.SqlUpdateOrInsertNotification, conn))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#Source", notificationMessage.Source);
cmd.Parameters.AddWithValue("#Sender", notificationMessage.Sender);
cmd.Parameters.AddWithValue("#NotificationType", notificationMessage.NotificationType);
cmd.Parameters.AddWithValue("#ReceivedTimestamp", notificationMessage.Timestamp);
cmd.Parameters.AddWithValue("#ContentJSon", notificationMessage.NotificationContent);
cmd.Parameters.AddWithValue("#ContentJsonHash", notificationMessage.ContentHashBytes);
await cmd.ExecuteNonQueryAsync();
}
}
I've also tried calling the stored procedure from SQL like this:
exec dbo.spUpdateOrInsertNotification 'foo', 'bar', 0,
'2017-12-05 15:23:41.207', '{}',
0xB966C33517993003D789EDF78DA20C4C491617F8F42F76F48E572ACF8EDFAC2A
Calling this twice returns 2 rows :(
I can do this, which works, hard coding the binary field I want to check
select *
from dbo.tblNotifications
where ContentJsonhash = 0xB966C33517993003D789EDF78DA20C4C491617F8F42F76F48E572ACF8EDFAC2A
Binary comparisons can be tricky. If you are using a true binary column, I believe length also comes into play. So even if those bytes are the same, and the lengths differ, the comparison would be false. An easy way is to convert these to strings:
alter procedure [dbo].[spUpdateOrInsertNotification]
#ContentJsonHash BINARY(32)
AS
DECLARE #NotificationId INT;
SET #NotificationId = (SELECT NotificationId
FROM dbo.tblNotifications n
WHERE convert(varchar(32), n.ContentJsonHash, 2) = convert(varchar(32), #ContentJsonHash, 2));
IF #NotificationId IS NOT NULL
BEGIN
-- Increment Count
END
ELSE
BEGIN
-- Insert new row.
END
I had an # where I shouldn't have had an ampersand.
SET #NotificationId = (SELECT #NotificationId
FROM dbo.tblNotifications n
WHERE convert(varchar(32), n.ContentJsonHash, 2) = convert(varchar(32), #ContentJsonHash, 2));
Should be
SET #NotificationId = (SELECT NotificationId
FROM dbo.tblNotifications n
WHERE convert(varchar(32), n.ContentJsonHash, 2) = convert(varchar(32), #ContentJsonHash, 2));
I feel so stupid for not noticing this sooner :(

Mathematical Function within Sql Case Statement

I am trying to come up with a sql statement which converts the odometer if stored in km to miles. If the odometer is stored in miles, it leaves as it is.
After the conversion, it then needs to check for Search paramters i.e Mileage.
The steps I have taken is using the Case Statement.
Here is my snippet of the select statement that I am using currently:
DECLARE
#Mileage NVARCHAR(75) = NULL,
#IsMiles BIT = 1,
#Converted NVARCHAR(75) = NULL
SELECT [Id],Odometer,IsMiles,
CASE IsMiles when 0 THEN OdometerValue * 0.62137
else Odometer end
FROM [dbo].[Vehicle]
where IsMiles = 0
Is there anyway to pass the Result of the case statement to ConvertedOdometer. I want to use that value to evaluate against the search Mileage parameters.
Something like this with this condition:
(ConvertedOdometer >=0 AND ConvertedOdometer <= #Mileage)
I am new to Case statement so have used these guides:
StackOverflow
Sql School
Some Blog
Perhaps something like this ...
DECLARE
#Mileage NVARCHAR(75) = NULL,
#IsMiles BIT = 1,
#Converted NVARCHAR(75) = NULL
select a.* from
(SELECT [Id],Odometer,IsMiles,
CASE when IsMiles=0 THEN OdometerValue * 0.62137 else Odometer end as ConvertedOdometer
FROM [dbo].[Vehicle]
where IsMiles = 0)a
where a.ConvertedOdometer >=0 AND
a.ConvertedOdometer <= #Mileage

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.