SQL Server : CASE in WHERE clause - sql

I need to create a SQL statement to check where condition if the column is null, it will do other condition. Below is my example:
SELECT
REPLACE(xxShip.Shipment_Date, '/', '-') AS ShipDate,xxShip.Customer,
xxShip.TravelSheetNo
FROM
(SELECT
RANK() OVER (PARTITION BY TravelSheetNo ORDER BY created_on DESC) AS shipwocode,
ShipDate, ShipTime, Shipment_Date,
Customer, Product_no, TravelSheetNo,
[status], ProcessLotNo
FROM
xxDEShipment) xxShip
WHERE
xxShip.shipwocode = 1
AND xxShip.TravelSheetNo = 'ABC'
--here i need to check the condition----------------------------
AND (CASE
WHEN ISNULL(xxShip.Shipment_Date,'') != '' OR xxShip.Shipment_Date != ''
THEN
xxShip.Shipment_Date IS NULL OR xxShip.Shipment_Date = ''
ELSE
CONVERT(DATETIME, xxShip.Shipment_Date) >= #DATESTART and CONVERT(DATETIME, xxShip.Shipment_Date) <= #DATEEND
END)
Please help. Thank you

This should be something like this:
AND(
(ISNULL(xxShip.Shipment_Date,'') <> '' AND
CONVERT(DATETIME, xxShip.Shipment_Date) >= #DATESTART AND
CONVERT(DATETIME, xxShip.Shipment_Date) <= #DATEEND
)
OR ISNULL(xxShip.Shipment_Date,'') == ''
)
Note that storing dates as strings is a bad practice.

If you need to select dates between #DATESTART and #DATEEND or null or empty date, use below:
ISNULL(CONVERT(DATETIME, NULLIF(xxShip.Shipment_Date, '')), #DATESTART)
BETWEEN #DATESTART AND #DATEEND

Related

case inside where clause which contains where conditions in db2

I have use case where I need to write a query which contains case statement in where clause with conditions like below :
I have column in 'SAMPLE_TABLE' called 'BIRTHDATE'
1) if only from date (which is a param i.e., :from) is given, then I need to get the records from SAMPLE_TABLE whose BIRTHDATE >= :from
2) if only to date (which is a param i.e., :to) is given,then get records whose BIRTHDATE <= :to
3) if both from and to dates are given, then get the records between those dates.
Below is the query I tried. But couldn't get the solution.
SELECT BIRTHDATE FROM SAMPLE_TABLE
WHERE
(CASE
WHEN (:from AND NOT :to)
THEN BIRTHDATE >= :receivefrom
WHEN (:to AND NOT :from)
THEN BIRTHDATE <= :to
WHEN (:to AND :from)
THEN BIRTHDATE BETWEEN :from AND :to
END)
Please provide a working query. Thanks in advance.
This code would do, when a date is not included leave it as blank. This was tested in SQL Server
declare #from date='1998-12-07'
declare #to date ='2000-12-07'
SELECT [Birthdate] --when only from is available
FROM SAMPLE_TABLE
where (case when (#to='' and #from !='') then 1 else 0 end)=1
and BIRTHDATE >= #from
UNION
SELECT [Birthdate] --when only to is available
FROM SAMPLE_TABLE
where (case when (#to!='' and #from ='') then 1 else 0 end)=1
and BIRTHDATE <= #to
UNION
SELECT [Birthdate] --when both from and to are avilable
FROM SAMPLE_TABLE
where (case when (#to!='' and #from !='') then 1 else 0 end)=1
and BIRTHDATE between #from and #to
Or else you can try this
declare #from date='1998-12-07'
declare #to date ='2000-12-07'
IF (#from!='' and #to!='')
SELECT [Birthdate]
FROM SAMPLE_TABLE
Where [Birthdate] between #from and #to
ELSE IF (#from='' and #to!='')
(SELECT [Birthdate]
FROM SAMPLE_TABLE
Where [Birthdate]<= #to)
ELSE IF (#from!='' and #to='')
(SELECT [Birthdate]
FROM SAMPLE_TABLE
Where [Birthdate]>= #from)
I think you simply want:
SELECT BIRTHDATE
FROM SAMPLE_TABLE
WHERE (BIRTHDATE >= :from OR :from IS NULL) AND
(BIRTHDATE <= :to OR :to IS NULL)
I assume that if some parameter is not supposed to be passed, then it has NULL value.
where birthdate between coalesce(:from, date('0001-01-01')) and coalesce(:to, date('9999-12-31'))

Query with Join of tables is taking long time to execute 5 min

SELECT
B.AccountBranchID
,B.VoucherNo
,B.BranchName AS BranchName
,B.InvoiceNo
,CONVERT(VARCHAR, B.InvoiceDate, 103) AS InvoiceDate
,CONVERT(VARCHAR, B.VoucherDate, 103) AS VoucherDate
,B.CustomerName
,B.RefID
,LN.AccountName AS LedgerName
,b.SalesPersonName AS SalesPersonName
,LN.LedgerCode
,B.AgentName
,B.ShipperName
,B.Segment
,B.TransactionType
,B.JobNo
,CONVERT(VARCHAR, B.JOBDate, 103) AS JOBDate
,B.MAWBNo
,B.HAWBNo
,B.AccountName
,B.LedgerCode AS AccountLedgerCode
,B.CurrencyCode
,ISNULL(B.Amount, 0) AS Amount
,B.ChargeExRate
,(CASE B.CRDR
WHEN 'CR' THEN (B.ChargeBaseAmount * -1)
ELSE B.ChargeBaseAmount
END) AS ChargeBaseAmount
,(CASE B.CRDR
WHEN 'CR' THEN 'Credit'
ELSE 'Debit'
END) AS CRDR
FROM VW_VoucherTR AS B
INNER JOIN VW_VoucherTR AS LN
ON B.VoucherID = LN.VoucherID
WHERE B.CompanyID = #CompanyID
AND (CASE #Type
WHEN 'I' THEN B.InvoiceDate
ELSE B.VoucherDate
END) BETWEEN ISNULL(#FromDate, (SELECT
FYearStart
FROM Secmst_FinancialYear
WHERE FyearId = #yearID)
) AND ISNULL(#ToDate, GETDATE())
AND (#Segment IS NULL
OR B.Segment = #Segment)
AND (#BranchMappingID IS NULL
OR B.BranchMappingID = #BranchMappingID)
AND B.VoucherTypeCode IN ('sv')
AND B.IsDeleted = 0
AND (B.GroupName <> 'Sundry Creditors'
AND B.GroupName <> 'Sundry Debtors')
AND LN.GroupName IN ('Sundry Debtors', 'Sundry Creditors')
The subquery in the BETWEEN is probably what is killing you. Have you looked at the execution plan?
BETWEEN ISNULL(#FromDate, (
SELECT FYearStart
FROM Secmst_FinancialYear
WHERE FyearId = #yearID
))
AND ISNULL(#ToDate, GETDATE())
What's happening is you are running that query across every row, and by my looks, that's unnecessary because you are only needing static dates there (not anything based on the joined rows.)
Try this:
DECLARE #FromDateActual datetime = ISNULL(#FromDate, (
SELECT FYearStart
FROM Secmst_FinancialYear
WHERE FyearId = #yearID
));
DECLARE #ToDateActual datetime = ISNULL(#ToDate, GETDATE());
SELECT B.AccountBranchID
,B.VoucherNo
,B.BranchName AS BranchName
,B.InvoiceNo
,convert(VARCHAR, B.InvoiceDate, 103) AS InvoiceDate
,convert(VARCHAR, B.VoucherDate, 103) AS VoucherDate
,B.CustomerName
,B.RefID
,LN.AccountName AS LedgerName
,b.SalesPersonName AS SalesPersonName
,LN.LedgerCode
,B.AgentName
,B.ShipperName
,B.Segment
,B.TransactionType
,B.JobNo
,convert(VARCHAR, B.JOBDate, 103) AS JOBDate
,B.MAWBNo
,B.HAWBNo
,B.AccountName
,B.LedgerCode AS AccountLedgerCode
,B.CurrencyCode
,ISNULL(B.Amount, 0) AS Amount
,B.ChargeExRate
,(
CASE B.CRDR
WHEN 'CR'
THEN (B.ChargeBaseAmount * - 1)
ELSE B.ChargeBaseAmount
END
) AS ChargeBaseAmount
,(
CASE B.CRDR
WHEN 'CR'
THEN 'Credit'
ELSE 'Debit'
END
) AS CRDR
FROM VW_VoucherTR AS B
INNER JOIN VW_VoucherTR AS LN ON B.VoucherID = LN.VoucherID
WHERE B.CompanyID = #CompanyID
AND (
CASE #Type
WHEN 'I'
THEN B.InvoiceDate
ELSE B.VoucherDate
END
) BETWEEN #FromDateActual
AND #ToDateActual
AND (
#Segment IS NULL
OR B.Segment = #Segment
)
AND (
#BranchMappingID IS NULL
OR B.BranchMappingID = #BranchMappingID
)
AND B.VoucherTypeCode IN ('sv')
AND B.IsDeleted = 0
AND (
B.GroupName <> 'Sundry Creditors'
AND B.GroupName <> 'Sundry Debtors'
)
AND LN.GroupName IN (
'Sundry Debtors'
,'Sundry Creditors'
)
Beyond that you could consider adding non-clustered indexes. The Query Analyzer may even suggest a couple. But you'll want to be careful there, depending on how the data is used and loaded, as too many indexes or large ones can lead to further performance issues in other places (row insertions, page fragmentation, etc).
There could be many reasons for it, but one thing is quite plain. The following part is not sargable.
(CASE #Type
WHEN 'I' THEN B.InvoiceDate
ELSE B.VoucherDate
END) BETWEEN ISNULL(#FromDate, (SELECT
FYearStart
FROM Secmst_FinancialYear
WHERE FyearId = #yearID)
) AND ISNULL(#ToDate, GETDATE())
Should be rewritten to be sargable, so that indexes can be used.
SELECT #FromDate = ISNULL(#FromDate, (SELECT
TOP 1 FYearStart
FROM Secmst_FinancialYear
WHERE FyearId = #yearID)) )
SELECT #ToDate = ISNULL(#ToDate, GETDATE())
SELECT
...
WHERE
...
AND
((#Type='I' AND B.InvoiceDate BETWEEN #FromDate AND #ToDate)
OR
(#Type<>'I' AND B.VoucherDate BETWEEN #FromDate AND #ToDate))
AND
...
Of course proper indexing is the way how to speed up your query, if no indexes are on InvoiceDate, VoucherDate, etc. then your query will use full table scan instead of index seek and it will be slow.

SQL Server : CASE-WHEN returns error in select list or Not-exist block if used in both

In the below SQL Server 2008 select statement Case-When is used in 2 places, in the select list and inside NOT EXISTS: CASE-1 and CASE-2.
It works only if I comment out one of case-when statements, only if I use it only in one place: select list OR not-exist.
If it used in both places, as below, I get error:
Conversion failed when converting date and/or time from character string.
I did my research, read http://www.fmsinc.com/free/newtips/sql/sqltip10.asp, but I still can not make it work.
Please help, what is wrong with code below? Thank you
MyTable.dob is nvarchar(10)
PayrollTable.date_of_birth is varchar(10)
Both dob columns are nullable.
MyTable.dob is in format mmddyy like '010255'.
PayrollTable.date_of_birth is in format 'mm/dd/yyyy' like '01/02/1955'
Code:
SELECT
FName,
LName,
( --- CASE-1
select
CASE
WHEN CONVERT(DATE, STUFF(STUFF(a.dob,3,0,'/'),6,0,'/')) > GETDATE()
THEN CONVERT(varchar(10), DATEADD(yy, -100, CAST(STUFF(STUFF(a.dob,3,0,'/'),6,0,'/') AS DATE)), 101)
ELSE CONVERT(varchar(10), CAST(STUFF(STUFF(a.dob,3,0,'/'),6,0,'/') AS DATE), 101)
END) as dob1
FROM
MyTable a
INNER JOIN
(SELECT
FName, LName, dob,
-- StartDate source format = yyyymm - 200104 , --- result = 2001-04-01 as DATE
MAX(CAST((STUFF(StartDate,5,0,'-') + '-01') AS DATE) ) as StartDate -- original format yyyymm
FROM
MyTable
WHERE
-- mmddyy
CAST(SUBSTRING( dob, 5, 2) as INT) > 31 --yy
AND dob != '999999'
GROUP BY
FName, LName, dob --'mmddyy'
) as t ON
LTRIM(RTRIM(a.FName)) = LTRIM(RTRIM(t.FName)) AND LTRIM(RTRIM(a.LName)) = LTRIM(RTRIM(t.LName))
AND
a.dob = t.dob --'mmddyy'
AND
CAST((STUFF(a.StartDate,5,0,'-') + '-01') AS DATE) = t.StartDate
WHERE ((LTRIM(RTRIM(a.FName)) != '' and
a.FName is not null) or
( LTRIM(RTRIM(a.LName)) != '' and a.LName is not null ) )
and
NOT EXISTS ----------------------------------
-- player does NOT exist in Party DIM alerady
(
select *
from PayrollTable p --- PARTY
where
p.date_of_birth = --t.dob -- varchar(10) 1980-09-07 p.date_of_birth
( -- CASE-2
select
CASE
WHEN CONVERT(DATE, STUFF(STUFF(t.dob,3,0,'/'),6,0,'/')) > CAST(GETDATE() as DATE) --t.dob
THEN CONVERT(varchar(10), DATEADD(yy, -100, CAST(STUFF(STUFF(t.dob,3,0,'/'),6,0,'/') AS DATE)), 101)
ELSE CONVERT(varchar(10), CAST(STUFF(STUFF(t.dob,3,0,'/'),6,0,'/') AS DATE), 101) --t.dob
END
)
and
p.first_name = t.FName
and
p.last_name = t.LName
)
your problem is here.
select *
from PayrollTable p --- PARTY
where
p.date_of_birth = --t.dob -- varchar(10) 1980-09-07 p.date_of_birth
( -- CASE-2
select
CASE
WHEN CONVERT(DATE, STUFF(STUFF(t.dob,3,0,'/'),6,0,'/')) > CAST(GETDATE() as DATE) --t.dob
THEN CONVERT(varchar(10), DATEADD(yy, -100, CAST(STUFF(STUFF(t.dob,3,0,'/'),6,0,'/') AS DATE)), 101)
-- MISSING A WHEN CONDITION HERE
THEN DATEADD(yy, -100, CAST(STUFF(STUFF('090780',3,0,'/'),6,0,'/') AS DATE))
ELSE CONVERT(varchar(10), CAST(STUFF(STUFF(t.dob,3,0,'/'),6,0,'/') AS DATE), 101) --t.dob
END
)

Where Clause doesn't Work - SQL Server

My previous question was this Case Statement With Between Clause In Sql Server
I got a solution and it works. But the problem is when I add another column to the WHERE clause, it won't filter with this new column:
SELECT
tbl1.Column1, tbl1.Column2
FROM
table1 tbl1
WHERE
EmployeeId = CASE WHEN #employeeId = '' THEN tbl1.EmployeeId
ELSE #employeeId END
AND (#DateTo = '1900-01-01' AND #DateFrom = '1900-01-01') OR
(NOT (#DateTo = '1900-01-01' AND #DateFrom = '1900-01-01')
AND (CAST(tbl1.txnDate AS DATE) BETWEEN #DateFrom AND #DateTo))
This code is what I am trying to use. But it doesn't work. I tried hard-coding a value for EmployeeId. But it doesn't work
You must Use ( and ) in where clause where you use And and OR together in order to define priority of each condition:
SELECT tbl1.Column1,tbl1.Column2
FROM table1 tbl1
WHERE EmployeeId = CASE WHEN #employeeId = '' THEN tbl1.EmployeeId ELSE #employeeId END
AND (
(#DateTo = '1900-01-01' AND #DateFrom = '1900-01-01')
OR (
NOT (#DateTo = '1900-01-01' AND #DateFrom = '1900-01-01')
AND (CAST(tbl1.txnDate AS DATE) BETWEEN #DateFrom AND #DateTo)
)
)

SQL Server : datetime incorrect results

Using SQL Server 2008,
I have a procedure as follows:
SELECT
UserId, Name, Company, LanguageId, CodeRegisteredWith, TotalLoggedInDuration,
Region, IsAdmin,
IsRep, IsRetailer, IsTeamLeader, [dateregistered]
FROM
RoundupAcademy.dbo.UserProfile WITH(NOLOCK)
WHERE
(Convert(smalldatetime, DateRegistered, 120) >= Convert(smalldatetime, '2013-1-1', 120)
AND (Convert(smalldatetime, DateRegistered, 120) <= convert(smalldatetime, '2013-8-8', 120)))
This works fine and shows the results between the dates.
However when expanding on this query and some more conditions as follows:
SELECT
UserId, Name, Company, LanguageId, CodeRegisteredWith, TotalLoggedInDuration,
Region, IsAdmin, IsRep, IsRetailer, IsTeamLeader, [dateregistered]
FROM
RoundupAcademy.dbo.UserProfile WITH(NOLOCK)
WHERE
UserId is not null OR UserId not like ''
AND
(#LanguageID = 0 OR ([LanguageID] = #LanguageID ))
AND
((Convert(smalldatetime, DateRegistered, 120) >= Convert(smalldatetime, #datereg, 120)
AND (Convert(smalldatetime, DateRegistered, 120) <= convert(smalldatetime, #dateend, 120))))
it seems any date shows.
not sure what the problem is as my other conditions look fine.
any ideas?
Replace
WHERE UserId is not null OR UserId not like ''
with
WHERE (UserId is not null OR UserId not like '')
Otherwise you would get all records where UserId is not null or the other conditions are true.
query should be like these
SELECT UserId, Name, Company, LanguageId, CodeRegisteredWith, TotalLoggedInDuration, Region, IsAdmin,
IsRep, IsRetailer, IsTeamLeader, [dateregistered] FROM RoundupAcademy.dbo.UserProfile WITH(NOLOCK)
WHERE( UserId is not null OR UserId not like '')
AND
(#LanguageID = 0 OR ([LanguageID] = #LanguageID ))
AND
((Convert(smalldatetime,DateRegistered, 120) >= Convert(smalldatetime,#datereg, 120)
AND (Convert(smalldatetime,DateRegistered, 120) <= convert(smalldatetime,#dateend, 120))))