I am working on an SSRS report that has a parameter as 'Quarter1', 'Quarter2', 'Quarter3' and 'Quarter4' and I have a query that needs to take the user value and get data for that quarter and my query looks like this if Quarter 1 is selected. am using VS 2010 BIDS for SSRS and SQL 2012 for database
Select
CASE WHEN MONTH(DateGenerated) <= 3 THEN '1Q/'
WHEN MONTH(DateGenerated) > 3 and MONTH(DateGenerated) <= 6 THEN '2Q/'
WHEN MONTH(DateGenerated) > 6 and MONTH(DateGenerated) <= 9 THEN '3Q/'
WHEN MONTH(DateGenerated) > 9 and MONTH(DateGenerated) <= 12 THEN '4Q/' END
as GenDate, Notes, Equation
from SubTask
where Year(DateGenerated) = #year and MONTH(DateGenerated) in (#Quarter)
When doing it in SSRS, I am not able to give months (1, 2 and 3) as value to Quarter1. Is there a way that I am missing. Appreciate the help..
Your parameter from SSRS will come over as a comma delimited string so we need a function to split the values.
For example, if your parameter is Quarter ... then your SQL would look like
Create Procedure xyz
#Quarter varchar(50) = null
as BEGIN
Select
CASE WHEN MONTH(DateGenerated) <= 3 THEN '1Q/'
WHEN MONTH(DateGenerated) > 3 and MONTH(DateGenerated) <= 6 THEN '2Q/'
WHEN MONTH(DateGenerated) > 6 and MONTH(DateGenerated) <= 9 THEN '3Q/'
WHEN MONTH(DateGenerated) > 9 and MONTH(DateGenerated) <= 12 THEN '4Q/' END
as GenDate, Notes, Equation
from SubTask
where Year(DateGenerated) = #year and MONTH(DateGenerated)
in (Select Value From dbo.FNSplit(#Quarter,','))
And the function is ...
CREATE FUNCTION [dbo].[FnSplit]
(
#List nvarchar(max),
#SplitOn nvarchar(5)
)
RETURNS #RtnValue table
(
Id int identity(1,1),
Value varchar(max)
)
AS
BEGIN
While (Charindex(#SplitOn,#List)>0)
Begin
Insert Into #RtnValue (value)
Select
Value = ltrim(rtrim(Substring(#List,1,Charindex(#SplitOn,#List)-1)))
Set #List = Substring(#List,Charindex(#SplitOn,#List)+len(#SplitOn),len(#List))
End
Insert Into #RtnValue (Value)
Select Value = ltrim(rtrim(#List))
Return
END
GO
Related
How to dynamic generate row from max value
for example if i am passing max value 7 Store procedure should return value
1
2
3
4
5
6
7
without using loops
If you are using sql server below query will serve you purpose:
create procedure generate_list
#maxLimit int
as
begin
SELECT DISTINCT n = number
FROM master..[spt_values]
WHERE number BETWEEN 1 AND #maxlimit
end
Then call the store procedure with :
exec generate_list 7
Output:
create PROCEDURE [dbo].GenerateSequence
#MaxLimit int
AS
BEGIN
;with numcte
AS
(
SELECT 1 [Sequence]
UNION all
SELECT [Sequence] + 1 FROM numcte WHERE [Sequence] < #MaxLimit
)
select * from numcte
END
I need to count how many men was working each hour. I have two tables:
Hour Men
------------
6 0
7 0
8 0
9 0
10 0
11 0
12 0
where "Men" column is the count of men. Another table is:
ClockedInHour ClockedOutHour
6 10
7 10
8 12
6 11
9 12
So for every entry in the second table, I need to increment "Men" column in the first table for every hour between "ClockedInHour" and "ClockedOutHour" including those in the table, and, if possible, to do it without cursor.
Additional condition: it will be a part of the table-valued function.
Thanks in advance for your help.
Solved!
DECLARE #Hour6 INT
SET #Hour6 = (SELECT COUNT(*) FROM #table2 where ClockedOutHour >= 6 and ClockedInHour <= 6)
DECLARE #Hour7 INT
SET #Hour7 = (SELECT COUNT(*) FROM #table2 where ClockedOutHour >= 7 and ClockedInHour <= 7)
DECLARE #Hour8 INT
SET #Hour8 = (SELECT COUNT(*) FROM #table2 where ClockedOutHour >= 8 and ClockedInHour <= 8)
DECLARE #Hour9 INT
SET #Hour9 = (SELECT COUNT(*) FROM #table2 where ClockedOutHour >= 9 and ClockedInHour <= 9)
DECLARE #Hour10 INT
SET #Hour10 = (SELECT COUNT(*) FROM #table2 where ClockedOutHour >= 10 and ClockedInHour <= 10)
DECLARE #Hour11 INT
SET #Hour11 = (SELECT COUNT(*) FROM #table2 where ClockedOutHour >= 11 and ClockedInHour <= 11)
DECLARE #Hour12 INT
SET #Hour12 = (SELECT COUNT(*) FROM #tc where ClockedOutHour >= 12 and ClockedInHour <= 12)
UPDATE #table1 SET Man = #Hour6 WHERE Hour = 6
UPDATE #table1 SET Man = #Hour7 WHERE Hour = 7
UPDATE #table1 SET Man = #Hour8 WHERE Hour = 8
UPDATE #table1 SET Man = #Hour9 WHERE Hour = 9
UPDATE #table1 SET Man = #Hour10 WHERE Hour = 10
UPDATE #table1 SET Man = #Hour11 WHERE Hour = 11
UPDATE #table1 SET Man = #Hour12 WHERE Hour = 12
You can do this using a Insert Trigger as:
Go --terminate all preceding batch of statements
CREATE TRIGGER tg_MenCount ON dbo.table2 For INSERT
AS
SET XACT_ABORT, NOCOUNT ON
--Ignore zero row updates, inserts
IF NOT EXISTS (SELECT * FROM INSERTED) RETURN;
BEGIN TRY
UPDATE T1
set T1.men = T1.men +1
FROM
table1 T1
INNER JOIN INSERTED I
ON T1.hour between I.ClockedInHour and I.ClockedOutHour
END TRY
BEGIN CATCH
IF XACT_STATE() <> 0 ROLLBACK TRANSACTION
--RAISERROR [rethrow caught error using #ErrorNumber, #ErrorMessage, etc]
END CATCH
GO
My question here is how do I use a variable to be a column name in a select statement. I have created the variable #B to be a column name that is BGNDATE1 through BGNDATE12. Rather than have 12 select statements I created a while loop. The column name is basically BGNDATE + the incremented integer.
The error I am getting is:
Conversion failed when converting the varchar value 'BGNDATE1' to data type int.
USE X --this is the database
DECLARE #DATES TABLE (ROWID INT, FISCDATES INT)
DECLARE #FY INT = 2012
DECLARE #I INT
DECLARE #IV VARCHAR(2)
DECLARE #B VARCHAR(9)
SELECT #FY AS FY
SET #I = 1
WHILE #I <= 12
BEGIN
SET #IV = #I
SET #B = 'BGNDATE' + #IV
INSERT INTO #DATES (ROWID)
SELECT #I
MERGE INTO #DATES AS T
USING (
--This is where the error is with regards to the variable #B
SELECT #B AS FISCDATES FROM DBO.Y -- Y is the table in the database
WHERE FSCYEAR = #FY) AS S
ON T.ROWID = #I
WHEN MATCHED
THEN UPDATE
SET T.FISCDATES = S.FISCDATES;
SET #I = #I + 1
END
SELECT * FROM #DATES
You can't use a variable as a column name (unless you create the entire query dynamically), but you can use a variable to select from different columns:
...
SELECT
CASE #IV
WHEN 1 THEN BGNDATE1
WHEN 2 THEN BGNDATE2
WHEN 3 THEN BGNDATE3
WHEN 4 THEN BGNDATE4
WHEN 5 THEN BGNDATE5
WHEN 6 THEN BGNDATE6
WHEN 7 THEN BGNDATE7
WHEN 8 THEN BGNDATE8
WHEN 9 THEN BGNDATE9
WHEN 10 THEN BGNDATE10
WHEN 11 THEN BGNDATE11
WHEN 12 THEN BGNDATE12
END AS FISCDATES FROM DBO.Y
...
When you select #B that won't work because #B is not a column name, it is a variable.
It would be best to denormalize the table so instead of having 12 columns named BGNDATE 1 through 12 you had another table to join to.
If you can't do that, do it with dynamic sql:
exec('MERGE INTO #DATES AS T
USING (
SELECT ' + #B + ' AS FISCDATES FROM DBO.Y
WHERE FSCYEAR = #FY) AS S
ON T.ROWID = #I
WHEN MATCHED
THEN UPDATE
SET T.FISCDATES = S.FISCDATES;')
Against SQL Server, I'm essentially trying to calculate a value based on Year to Date, so I want to sum any values from July 16, 2012 and prior and display them. I'm using the following query (note that I've replaced parameters with simple integers to calculate the value for today):
SELECT SUM(CASE
WHEN (
(
dns.ODAY <= 16
AND (dns.fiscalyear + 1) = 13
AND dns.omonth = 7
)
OR
(
(dns.fiscalyear + 1) = 13
AND dns.omonth < 7
)
)
THEN dns.QtyShipped
ELSE 0
END) AS Shipped_Units
FROM myTable dns
However, this query is returning 0 for all rows. If I replace dns.QtyShipped with an integer, say 1, it still returns 0. So obviously the case statement isn't being evaluated correctly. Is my logic flawed? Or is it a syntax issue (e.g. I need more parentheses)?
Thanks!
Additional comments:
To test, I've ran the following query:
SELECT SUM(dns.QtyShipped)
FROM myTable dns
where
(dns.ODAY <= 16
AND (dns.fiscalyear + 1) = 13
AND dns.omonth = 7)
OR
((dns.fiscalyear + 1) = 13
AND dns.omonth < 7)
Which returns a very large number. This is confusing.
The code that you mentioned earlier is working absolutely fine. Please double check the values you are using to evaluate the conditions. For example, please confirm if for fiscalyear the value is 2013 or 13. I've used variables instead of column names in the code mentioned below and its returning the expected results:
declare #ODAY integer
set #ODAY=17
declare #fiscalyear int
set #fiscalyear=12
declare #omonth int
set #omonth=8
SELECT SUM(CASE
WHEN (
(
#ODAY <= 16
AND (#fiscalyear + 1) = 13
AND #omonth = 7
)
OR
(
(#fiscalyear + 1) = 13
AND #omonth < 7
)
)
THEN 1
ELSE 0
END) AS Shipped_Units
If I had to guess I would say that your year is being stored as 4 digits. At least that is the problem I ran into when I set up my test.
When I set up this test it worked:
CREATE TABLE myTable (fiscalyear int, omonth int, ODAY int, qtyshipped int)
INSERT INTO myTable VALUES (2012,1,1,1),
(12,1,1,1),
(12,2,1,1),
(12,3,1,1),
(12,4,1,1),
(13,1,1,1),
(12,7,1,1)
When I set up this test it failed:
CREATE TABLE myTable (fiscalyear int, omonth int, ODAY int, qtyshipped int)
INSERT INTO myTable VALUES (2012,1,1,1),
(2012,1,1,1),
(2012,2,1,1),
(2012,3,1,1),
(2012,4,1,1),
(2013,1,1,1),
(2012,7,1,1)
Is there any reason you aren't using actual dates? Your logic would be much simpler and if the dates are stored in your table then the query would probably be faster too.
EDIT: Here is an additional test you can run to be sure its your case causing the problem:
SELECT SUM(CASE
WHEN (
(
dns.ODAY <= 16
AND (dns.fiscalyear + 1) = 13
AND dns.omonth = 7
)
OR
(
(dns.fiscalyear + 1) = 13
AND dns.omonth < 7
)
)
THEN 0
ELSE dns.QtyShipped
END) AS Shipped_Units
FROM myTable dns
Basically flip the case around. Return 0 if you are true and the QtyShipped if not. If you get a value this way then the problem is in your case, if you don't then the problem is probably somewhere else in your query.
i'm playing around with building a sql function that will extract numbers from a title, which is what the following code below does. Although, i want to modify this function to parse numbers into sections. For example:
Current Data in title field:
QW 1 RT 309-23-1
QW 1 RT 29-1
QW 1 RT 750-1
QW RT 750-1
Temp tables created once function is ran on title field:
column 1 Column 2 Column 3 Column 4
1 309 23 1
1 29 1 Null
1 750 1 Null
Null 750 1 Null
create function [dbo].[ExtractNumbers](#Numbers nvarchar(2000))
returns nvarchar(2000)
as
BEGIN
declare #NonNumericIndex int
set #NonNumericIndex = PATINDEX('%[^0-9]%',#Numbers)
WHILE #NonNumericIndex > 0
begin
SET #Numbers = REPLACE(#Numbers,SUBSTRING(#Numbers,#NonNumericIndex,1),'')
SET #NonNumericIndex = PATINDEX('%[^0-9]%',#Numbers)
SET
end
return #Numbers
END
Here's one way.
Although actually at the end I realised the format was more fixed than I had originally realised so you may be better off just using the various string manipulation functions to calculate the columns directly.
WITH TestTable AS
(
SELECT 'QW 1 RT 309-23-1' AS title UNION ALL
SELECT 'QW 1 RT 29-1' UNION ALL
SELECT 'QW 1 RT 750-1' UNION ALL
SELECT 'QW RT 750-1'
)
SELECT title, [1] AS [Column 1], [2] AS [Column 2],[3] AS [Column 3],[4] AS [Column 4]
FROM TestTable CROSS APPLY dbo.GetNumbers(title)
PIVOT
(MAX(num) FOR idx IN ([1], [2],[3],[4])
) AS PivotTable;
Uses the following TVF
CREATE FUNCTION GetNumbers
(
#Numbers NVARCHAR(2000)
)
RETURNS #Results TABLE
(
idx INT IDENTITY(1,1),
num INT
)
AS
BEGIN
DECLARE #NonNumericIndex INT, #NumericIndex INT
SET #NumericIndex = PATINDEX('%[0-9]%',#Numbers)
IF (#NumericIndex > 4) --First Column not there
INSERT INTO #Results VALUES (NULL)
WHILE #NumericIndex > 0
BEGIN
SET #Numbers = RIGHT(#Numbers,LEN(#Numbers)-#NumericIndex+1)
SET #NonNumericIndex = PATINDEX('%[^0-9]%',#Numbers)
IF(#NonNumericIndex = 0)
BEGIN
INSERT
INTO #Results VALUES (#Numbers)
RETURN
END
ELSE
INSERT
INTO #Results VALUES
(LEFT(#Numbers,#NonNumericIndex-1))
SET #Numbers = RIGHT(#Numbers,LEN(#Numbers)-#NonNumericIndex+1)
SET #NumericIndex = PATINDEX('%[0-9]%',#Numbers)
END
RETURN
END