Problem: I am doing multiple case statments, however it returns only as one column. I would like multiple columns returned.
Current Code
declare #currentweek as nvarchar(10)
declare #1stweek as nvarchar(10)
declare #2ndweek as nvarchar(10)
set #currentweek= convert(varchar(10),dateadd(ww,0,GETDATE()),110)
set #1stweek= convert(varchar(10),dateadd(ww,1,GETDATE()),110)
select
case
when [date] < #currentweek then 'R'
when [date] > #currentweek and [date]<#1stweek then 'R'
else null
end [current week],[first week]
What I am trying to see is multiple columns. If the condition is met then the value R will be placed in either the [first week] or [current week] column.
Thanks
You need to do two different Case statements - one for each column:
select case when [date] < #currentweek then 'R'
else null
end as [current week],
case when [date] > #currentweek
and [date] < #1stweek then 'R'
else null
end as [first week]
Related
I am attempting to define and new column called End Year that is the calculation of another column plus a number representing number of years. For some reason my script does not recognize the new column called Allocation Year using the excerpt below SQL statement in SQL Server 2008. Note that Contract Year is an existing column that is identified in the non-redacted full script:
,[Allocation Type] =
CASE
WHEN left([contract type] ,1)'1' = THEN 'O&M'
ELSE 'N/A'
END
,[Allocation Year] =
CASE
WHEN [Contract Year]='XXXX' THEN '0'
ELSE CAST ([Contract Year] AS INT)
END
,[End Year] =
CASE
WHEN [Allocation Type]='O&M' THEN [Allocation Year] + 6
END
Columns are named with the AS keyword (which can also be elided in many cases), not with the = operator.
SQL Server does not let you reference other columns or aliases in a SELECT clause - you have to use a subquery:
Like so:
SELECT
*,
CASE WHEN [Allocation Type] = 'O&M'
THEN [Allocation Year Temp] + 6
ELSE NULL
END AS [Allocation Year]
FROM
(
SELECT
CASE WHEN LEFT( [Contract type], 1 ) = '1'
THEN 'O&M'
ELSE 'N/A'
END AS [Allocation Type],
CASE WHEN [Contract Year] = 'XXXX'
THEN '0'
ELSE CAST( [Contract Year] AS int )
END AS [Allocation Year Temp],
*
FROM
....
)
If you want to put everything in one select query, then try this one. Hope this helps. Thanks.
,[End Year] =
CASE
WHEN left([contract type] ,1)='1' THEN
(CASE
WHEN [Contract Year]='XXXX' THEN 6
ELSE (CAST ([Contract Year] AS INT) + 6 )
END)
END
You cannot reference computed columns in the SELECT statement. You'll have to repeat the calculation (or use subqueries like Dai suggested):
,[Allocation Type] =
CASE
WHEN left([contract type] ,1)='1' THEN 'O&M'
ELSE 'N/A'
END
,[Allocation Year] =
CASE
WHEN [Contract Year]='XXXX' THEN 0
ELSE CAST ([Contract Year] AS INT)
END
,[End Year] =
CASE
WHEN left([contract type] ,1)='1' THEN (CASE
WHEN [Contract Year]='XXXX' THEN 0
ELSE CAST ([Contract Year] AS INT)
END) + 6
END
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.
Can anyone please help me figure out a more convenient and efficient (shortest) way of writing the below script? The reason I'm doing this is because I will end up using the script on SSRS.
On SSRS, there will be two parameters and both are set to take blank values.
If the user running SSRS indicated only the Starting date parameter, then my report should give any date >= the starting date.
If the user put dates on both #startingdate and #endingdate, my script will search only those that are between #startingdate and #endingdate.
Do you guys kinda get what I'm trying to accomplish? I have an SSRS report similar to this scenario but it's very cumbersome to update because if I update one of the statement, I would have to do it on the other ones. Also the script is big and repetitive because of this.
If you could help me figure out a better way to do shorten or make it less cumbersome to code, please let me know, thanks!
Below is a sample script that I use:
DECLARE #STARTINGDATE
DECLARE #ENDINGDATE
SET #STARTINGDATE = '10/01/2013'
SET #ENDINGDATE = '10/05/2013'
CASE
WHEN #STARTINGDATE <> '' AND #ENDINGDATE <> ''
SELECT * FROM SALESTABLE
WHERE SALESDATE BETWEEN #STARTINGDATE AND #ENDINGDATE
END
WHEN #STARTINGDATE = '' AND #ENDINGDATE = ''
SELECT * FROM SALESTABLE
END
WHEN #STARTING <> '' AND #ENDINGDATE = ''
SELECT * FROM SALESABLE
WHERE SALESDATE >= #STARTINGDATE
END
WHEN #ENDINGDATE <> '' AND #STARTINGDATE = ''
SELECT * FROM SALESABLE
WHERE SALESDATE <= #ENDINGDATE
END
what if u use IF ELSE Statement?
IF #STARTINGDATE IS NOT NULL AND #ENDINGDATE IS NULL
SELECT * FROM SALESTABLE WHERE SALESDATE >= CONVERT(DATE,#STARTINGDATE,103)
ELSE IF #STARTINGDATE IS NOT NULL AND #ENDINGDATE IS NOT NULL
SELECT * FROM SALESTABLE WHERE SALESDATE >= CONVERT(DATE,#STARTINGDATE,103)
AND SALESDATE<DATEADD(DAY,1,CONVERT(DATE,#ENDINGDATE,103))
ELSE
SELECT * FROM SALESTABLE
References http://sqlfiddle.com/#!3/783c03/12
You can try this if StartingDate and EnddingDate dates are string. Using StartingDate and EnddingDate as text you will loose the date picker functionality in SSRS. Anyway here is a method to shorten the above script
Select * FROM SalesTable
Where SalesDate between
CASE WHEN #StartingDate = '' THEN SalesDate ELSE #StartingDate END
AND CASE WHEN #EndingDate = '' THEN SalesDate ELSE #EndingDate END
Method 2
If StartingDate and Endding date are dateTime. Use this method:
FYI: SSRS doesn't allow Blank values for DateTime parameters. It only allows NULL.
First create two parameters StartingDate and EndingDate and check the Allow NULL value.
Your Dataset query will be something like this
SELECT * FROM SalesTable
Where (SalesDate IS NULL OR #StartingDate IS NULL)
OR (SalesDate between ISNULL(#StartingDate, SalesDate)
AND ISNULL(#EndingDate, SalesDate))
Assign you dataset parameters to report parameters
Now your are good to go.
There are thee input parameter in my stored procedure. for example,
DECLARE #fromDate DateTime = NULL
DECLARE #toDate DateTime = NULL
DECLARE #Id int = NULL
I want to write a condition in where clause like...if fromDate is provided then searching must be done on #fromDate. if #fromDate is not provided then check for #Id variable if this is not null then search basis on #Id...
Something like...
where
CASE
when #fromDate is not null
THEN (#FromDate is null or ([Created] between #FromDate and #ToDate))
ELSE (#requestId is null or Id=#requestId)
there is one problem with below solution...if #fromDate and #Id both are provided then this will do intesect of them and nothing is return.....condition should be like...if #fromDate is given the priority gives to #fromDate even if #Id is provided and result must not be dependend to #Id parameter....
Because you depend on both parameters you than can use them both in condition:
where
(#FromDate is null or ([Created] between #FromDate and #ToDate))
or
((#requestId is null or Id=#requestId)
and #FromDate is null) ----mix #requestId & #FromDate
Do you mean this? Please check:
WHERE [Created] BETWEEN
(CASE WHEN #FromDate IS NOT NULL THEN #FromDate ELSE [Created] END) AND
(CASE WHEN #ToDate IS NOT NULL THEN #ToDate ELSE [Created] END) AND
Id=(CASE WHEN #requestId IS NOT NULL THEN #requestId ELSE Id END)
I want to get all records entered with specific day, for example today:
ALTER PROCEDURE [dbo].[SP_GET_QUEUESINFO_BY_DATE]
#date nvarchar = '2012-09-21'
AS
BEGIN
declare #dateStart nvarchar(50) = #date + ' 00:00:00.0'
declare #dateEnd nvarchar(50) = #date + ' 23:59:59.437';
declare #returnData table (allQueue int,inQueue int,outQueue int)
SELECT 'table1' as table_name, COUNT(*)
FROM Queue as Counts
UNION ALL
SELECT 'table2' as table_name,COUNT(*) FROM Queue as Counts
WHERE QueueDate BETWEEN #dateStart AND #dateEnd
AND QueueNumIn != 0
END
Edited :
I Edited my code now it works :
ALTER PROCEDURE [dbo].[SP_GET_QUEUESINFO_BY_DATE]
AS
BEGIN
declare #date2 datetime
set #date2= '2012-09-21'
SELECT 'AllQueue' as table_name, COUNT(*)
FROM Queue as sdfds
UNION ALL
SELECT 'InQueue' as table_name,COUNT(*)
FROM Queue as sdfds
WHERE QueueDate >=#date2
AND QueueNumIn != 0
UNION ALL
SELECT 'OutQueue' as table_name, COUNT(*) FROM Queue as sdfds
WHERE QueueDate >=#date2
AND QueueNumOut != 0
END
It returns three records:
One problem is that the second column has no name. Why? Also, I want to return just one record that has three rows, not 3 separate records that have 2 fields.
you need to cast your varchar to datetime. and i think you want to assign Counts alias to Count(*)
ALTER PROCEDURE [dbo].[SP_GET_QUEUESINFO_BY_DATE]
#date nvarchar = '2012-09-21'
AS
BEGIN
declare #dateStart DATETIME = CAST(#date AS DATETIME)
declare #dateEnd DATETIME = DATEADD(hh,24,CAST(#date AS DATETIME))
declare #returnData table (allQueue int,inQueue int,outQueue int)
select 'table1' as table_name,COUNT(*) as Counts from QUEUE AS tb1
union all
select 'table2' as table_name,COUNT(*) as Counts from QUEUE AS tb2 where QueueDate >= #dateStart and QueueDate < #dateEnd and QueueNumIn !=0
END
not sure why returning all if you only want those in the spetial date.
Also, is better not to use between in Dates
ALTER PROCEDURE [dbo].[SP_GET_QUEUESINFO_BY_DATE]
#date datetime = '2012-09-21'
AS
BEGIN
select count(*) as 'AllQueue' ,
sum(case when QueueDate >=#date and QueueNumIn != 0 THEN 1 else 0 end) as 'InQueue',
sum(case when QueueDate >=#date and QueueNumOut != 0 THEN 1 else 0 end) as 'OutQueue'
from Queue
END
this should work.
this will give you something like
Allqueue inqueue, outqueue
----------------------------------------------------
11 | 8 | 10
This Code Worked and is edited code from ElVieejo
ALTER PROCEDURE [dbo].[SP_GET_QUEUESINFO_BY_DATE]
AS
BEGIN
declare #date2 datetime
set #date2= '2012-09-21'
select COUNT(QueueID) ,
sum(case when QueueNumIn != 0 THEN 1 else 0 end) as 'InQueue',
sum(case when QueueNumOut != 0 THEN 1 else 0 end) as 'OutQueue'
from Queue where QueueDate >= #date2
END