If Else in where clause - sql-server-2008

Here is a snippet of what I have:
select something from myTable
where curentFlag = 'Y'
and
case when #Year2 is not NULL then
AYEAR >= #Year AND AYEAR <= #Year2
else
AYEAR= isnull(#Year ,AYEAR)
end
ADATE = ISNULL(#Date, ADATE)
But this yields:
Incorrect syntax near '>'.
Incorrect syntax near 'ADATE'.
The user should be able to search by a year (equals to) or a year range. So I'm either passing in just #YEAR or both #YEAR and #YEAR2. So let's say my data set:
DECLARE #y TABLE(AYEAR INT);
INSERT #y VALUES(2008),(2010),(2010);
Now I have these variables:
DECLARE #YEAR INT, #YEAR2 INT;
If I pass in #YEAR = 2008 I should get 1 result.
If I pass in #YEAR = 2010 I should get 2 results.
If I pass in #YEAR = 2008 and #YEAR2 = 2010 I should get all 3 results.

CASE is an expression that returns a single value. It cannot be used for control of flow logic.
If you are sure that #Year will always be populated and #Year2 will only sometimes be populated, than this much simpler logic should work:
WHERE CURRENTFLAG = 'Y'
AND AYEAR BETWEEN #Year AND COALESCE(#Year2, #Year)
AND ADATE = COALESCE(#Date, ADATE);
You can try it with a very simple example:
DECLARE #y TABLE(AYEAR INT);
INSERT #y VALUES(2008),(2010),(2010);
DECLARE #YEAR INT = 2008, #YEAR2 INT = 2010;
--DECLARE #YEAR INT = 2008, #YEAR2 INT = NULL;
--DECLARE #YEAR INT = 2010, #YEAR2 INT = NULL;
SELECT AYEAR FROM #y
WHERE AYEAR BETWEEN #YEAR AND COALESCE(#YEAR2, #YEAR);

where CURRENTFLAG = 'Y'
case when #Year2 is not NULL then --after THEN should be statement or BEGIN block not AND
and AYEAR >= #Year AND AYEAR <= #Year2
else
AND AYEAR= isnull(#Year ,AYEAR) -- here also
end
and ADATE = ISNULL(#Date, ADATE)

Related

SSRS show list of weeks

Is there a way I can create a list of weeks (param):w1,W2,... based on another param list (years), so the first list is for the years and the second is for the weeks corresponding to the chosen year.
For example if I choose 2017 from my first list my second list (weeks) should be updated with labels W1,W2,... & the values are the corresponding dates in the given year.
Try this ...
declare #year as int
declare #startdate as datetime
declare #wk as int
declare #endwk as datetime
declare #tbl as table (
tbl_wk int,
tbl_Monday datetime
)
set #endwk= (SELECT DATEPART(wk, GETDATE())+1)
set #wk = 1
set #year = '2017'
set #startdate = CAST (cast(#year as varchar(4))+ '/01/01 00:00:00' as datetime)
while (#wk < #endwk)
begin
insert into #tbl (tbl_wk,tbl_Monday)
select #wk,DATEADD(wk, DATEDIFF(wk,0,#startdate), 0) as monday--MondayOfCurrentWeek,
set #wk = #wk+1
set #startdate = #startdate+7
end
select * from #tbl
You could adapt this to create a table in SQL and then reference this in your report.
Note: You could include Year in an outer loop if you need dates from more than one year
declare #year as int
declare #startdate as datetime
declare #wk as int
declare #tbl as table (
tbl_wk int,
tbl_Monday datetime
)
set #wk = 1
set #year = '2017'
set #startdate = CAST (cast(#year as varchar(4))+ '/01/01 00:00:00' as datetime)
while (#wk < 53)
begin
insert into #tbl (tbl_wk,tbl_Monday)
select #wk,DATEADD(wk, DATEDIFF(wk,0,#startdate), 0) as monday--MondayOfCurrentWeek,
set #wk = #wk+1
set #startdate = #startdate+7
end
select * from #tbl

stored procedure returns wrong value

I have a stored procedure that keeps giving me wrong answer. I asked the procedure to return the value of motor insurance. I run the procedure and give me the total of motor insurance premium but if I run it for the 4th time it give me the ageRange select statement value.
I moved the code into a new procedure but still the same.
My code
DELIMITER $$
CREATE DEFINER=`root`#`localhost` PROCEDURE `cal_motor_qoute`(in
coverID int , in dob date,
in sumMotor double , out QMsg varchar(200))
BEGIN
declare policy_cover , total , insRatio, ageExtra double;
declare ageRange int;
declare price_list varchar(200);
SELECT DATEDIFF(NOW(),dob) / 365.25 AS ageRange from dual;
if (coverID = 1) then
set policy_cover = 0.002;
elseif (coverID = 2) then
set policy_cover = 0.0025;
elseif (coverID = 3) then
set policy_cover = 0.003;
elseif (coverID = 4) then
set policy_cover = 0.0035;
end if;
if ( ageRange < 25) then
set ageExtra = 0.0005;
else
set ageExtra = 0.000;
end if;
set insRatio = policy_cover + ageExtra;
set total = (sumMotor * insRatio )* 10;
set QMsg = concat('total Premium is: ',total);
select #QMsg;
END
Any help please..
SELECT DATEDIFF(NOW(),dob) / 365.25 AS ageRange from dual;
will not set the variable ageRange, but it will do a select (of the calculated value) and name the column of the resultset ageRange.
The (or rather: one) way to set the value of your variable is to use into:
SELECT DATEDIFF(NOW(),dob) / 365.25 into ageRange from dual;
Although this is probably not the most precise way to calculate the age of a person anyway. You might want to replace
if ( ageRange < 25) then
with
if ( dob > date_sub(now(), interval 25 year) ) then

Check Each Date In Date Range

In SQL Server 2008 I have a startdate and an enddate being passed to my procedure. I need to check each date in the range to see if it exists in my validworkday table. I have no clue where to begin on this, but this is how start/end day are set-up
Declare #startdate date, #enddate date
Set #startdate = '01/01/2015'
Set #enddate = '04/16/2015'
Now how can I iterate each date in this span to see if validworkday = true for it? The check I would need to run is like so (checking each date)
Select isvalidworkday
from validworkdays
where date = '01/01/2015'
Select isvalidworkday
from validworkdays
where date = '01/02/2015'
This is syntax that I found from #Incidently years ago (I don't remember where that original post is, but hopefully this will be enough to give the credit), that I still use today. All I did was slightly tweak his syntax to insert the data into a temp table and add a cursor to iterate each individual date.
DECLARE #DateFrom smalldatetime, #DateTo smalldatetime, #firstdate date;
SET #DateFrom='20000101';
SET #DateTo='20081231';
-------------------------------
WITH T(date)
AS
(
SELECT #DateFrom
UNION ALL
SELECT DateAdd(day,1,T.date)
FROM T
WHERE T.date < #DateTo
)
SELECT date
INTO #AllDates
FROM T OPTION (MAXRECURSION 32767);
Declare c1 Cursor For
Select date
FROM #AllDates
Open c1
Fetch Next From c1 Into #firstdate
While ##FETCH_STATUS = 0
Begin
--Do whatever processing you need here
Fetch Next From c1 Into #firstdate
End
Close c1
Deallocate c1
Code should only live in one place and not be rewritten. Create functions (once) like GetAllIntsBetween(), GetAllMonths(), GetAllDates(), etc. Then used them like:
DECLARE #startdate date = '01/01/2015', #enddate date = '04/16/2015'
SELECT allDates.TheDate,
isnull(v.isvalidworkday, false) AS isvalidworkday
FROM dbo.GetAllDates(#startdate, #enddate) AS allDates
LEFT JOIN validworkdays AS v
ON allDates.TheDate = v.MyDate
The GetAllDates() would be:
CREATE FUNCTION dbo.GetAllDates(#Start DATETIME, #End DATETIME)
RETURNS
#AllDates TABLE
(
TheDate DATETIME
)
AS
BEGIN
IF #Start > #End
BEGIN
DECLARE #Temp DATETIME
SET #Temp = #Start
SET #Start = #End
SET #End = #Temp
END
WHILE #Start <= #End
BEGIN
INSERT INTO #AllDates
VALUES(#Start)
SET #Start = DATEADD(DAY, 1, #Start)
END
RETURN
END
(note: can change DATETIME to DATE)

I want to optimize this SQL Query

I have query like this:
DELIMITER $$
USE `kpbaru`$$
DROP PROCEDURE IF EXISTS `getAllUmurPegawai`$$
CREATE DEFINER=`root`#`localhost` PROCEDURE `getAllUmurPegawai`(IN id_user VARCHAR(20),i_tahun INT)
BEGIN
DECLARE currdate INT;
DECLARE birthdate INT;
DECLARE numRows INT;
DECLARE numIteration INT;
DECLARE tempMonth INT;
DECLARE umur INT;
SET numRows = (SELECT COUNT(*) FROM pegawai);
SET numIteration = 1;
WHILE numIteration <= numRows DO
SET currdate = i_tahun;
SET birthdate = (SELECT EXTRACT(YEAR FROM (SELECT TGL_LAHIR FROM pegawai WHERE INDEXING = numIteration AND ID_USER=id_user)));
SET umur = currdate - birthdate;
SET tempMonth = (SELECT EXTRACT(MONTH FROM (SELECT TGL_LAHIR FROM pegawai WHERE INDEXING = numIteration AND ID_USER=id_user)));
IF umur < 56 THEN
UPDATE pegawai SET pegawai.STATUS_PEGAWAI='Belum Pensiun',pegawai.BULAN_PENSIUN=tempMonth,STATUS_PENSIUN=1 WHERE pegawai.INDEXING = numIteration AND ID_USER=id_user;
ELSE
IF umur = 56 THEN
UPDATE pegawai SET pegawai.STATUS_PEGAWAI='Pensiun',pegawai.BULAN_PENSIUN=tempMonth,STATUS_PENSIUN=1 WHERE pegawai.INDEXING = numIteration AND ID_USER=id_user;
ELSE
UPDATE pegawai SET pegawai.STATUS_PEGAWAI='Pensiun',pegawai.BULAN_PENSIUN=tempMonth,STATUS_PENSIUN=0 WHERE pegawai.INDEXING = numIteration AND ID_USER=id_user;
END IF;
END IF;
SET numIteration = numIteration + 1;
END WHILE;
END$$
DELIMITER ;
i want to optimize this query, because this query will search each age in eeach people. This query runs very slow if we have big data (>1000 rows). Any one know how to optimize it?
I've tried some query like this:
UPDATE pegawai AS p LEFT JOIN(SELECT INDEXING, CAST(CASE WHEN (i_tahun - EXTRACT(YEAR FROM(SELECT TGL_lAHIR FROM pegawai WHERE ID_USER=id_user))) < 56 THEN 'Belum Pensiun' ELSE 'Pensiun' END AS VARCHAR(20))AS statusPegawai, EXTRACT(MONTH FROM(SELECT TGL_LAHIR FROM pegawai WHERE ID_USER=id_user))AS bulanPensiun, CAST(CASE WHEN (i_tahun - EXTRACT(YEAR FROM(SELECT TGL_lAHIR FROM pegawai WHERE ID_USER=id_user))) <= 56 THEN 1 ELSE 0 END AS INT)AS statusPensiun FROM pegawai WHERE ID_USER=id_user GROUP BY INDEXING)AS m
ON p.ID_USER = m.ID_USER
SET p.STATUS_PEGAWAI = m.statusPegawai, p.BULAN_PENSIUN = m.bulanPensiun, p.STATUS_PENSIUN = m.statusPensiun
WHERE p.ID_USER = id_user;
but it still wrong. Here the error is:
Query :
CREATE DEFINER=`root`#`localhost` PROCEDURE `getAllUmurPegawai`(in id_user varchar(20),i_tahun int) BEGIN DECLARE currdate INT;...
Error Code : 1064
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'varchar(20))as statusPegawai, extract(month from(select TGL_LAHIR from pegawai w' at line 29
Solution will be apreciated! :D
You cannot cast to varchar use char instead.
From the mysql documentation
The CONVERT() and CAST() functions take an expression of any type and produce a result value of a specified type.
The type for the result can be one of the following values:
- BINARY[(N)]
- CHAR[(N)]
- DATE
- DATETIME
- DECIMAL[(M[,D])]
- SIGNED [INTEGER]
- TIME
- UNSIGNED [INTEGER]
If I am reading your query correctly I think you can do this in a single update statement for a user:-
UPDATE pegawai
SET STATUS_PEGAWAI = IF(i_tahun - YEAR(TGL_LAHIR) < 56, 'Belum Pensiun', 'Pensiun'),
BULAN_PENSIUN = MONTH(TGL_LAHIR),
STATUS_PENSIUN = IF(i_tahun - YEAR(TGL_LAHIR) <= 56, 1, 0)
WHERE ID_USER=id_user

Stripping the time out of datetime SQL Server 2005

I think I'm going crazy here.
I am trying to do a SP on SQL Server 2005 which takes a date, looks it up in another table and assigns a period number and week number (for financial calendar purposes).
The output needs to hold the date as a string, rather than datetime.
I simply CANNOT get the date to show without the time behind it.
I have tried a couple of methods:
select cast(floor(cast(#CalcDate as float)) as datetime)
I have made a function which converts it into a string and puts it back out again:
CREATE FUNCTION dbo.DateToVarchar (#DateIn datetime)
RETURNS varchar(10)
AS
BEGIN
declare #DD [varchar] (2)
declare #MM [varchar] (2)
declare #YYYY [varchar] (4)
declare #DateOut [varchar] (10)
declare #DDLen [int]
declare #MMLen [int]
set #DD = datepart(dd,#DateIn)
set #DDLen = len(#DD)
set #DD = (case when #DDLen < 2 then '0' + #DD else #DD end)
set #MM = datepart(mm,#DateIn)
set #MMLen = len(#MM)
set #MM = (case when #MMLen < 2 then '0' + #MM else #MM end)
set #YYYY = datepart(yyyy,#DateIn)
set #DateOut = #YYYY + '-' + #MM + '-' + #DD
return #DateOut
END
When I run the above function outside of the SP I get the date back just fine. When I run it through the SP it comes back as 2012-12-30 00:00:00.000
The variable #CalcDate is declared as a varchar(10)
Any ideas?
Thanks in advance
EDIT
Here is the body of the SP so far:
declare #StartDate [datetime]
, #EndDate [Datetime]
, #CalcDate [datetime] --This number will change in the WHILE loop to reflect the increment of days
, #Week [varchar]
, #Period [varchar]
, #i [int]
, #Year [int]
, #CalcDay [int]
, #CalcMonth [int]
, #CalcYear [int]
, #ConcatDate [char] (10)
set #StartDate = '2012-12-30'
set #EndDate = '2013-01-28'
set #Year = 2013
set #i = -1
-- Going to do a while loop here and instead of Week number and Period Number I'm going to do some calculations
set #Week = (Select WeekNum from aaGreensPeriodListTest Where PeriodNum = 1 and WeekNum = 1)
set #Period = (Select PeriodNum from aaGreensPeriodListTest Where PeriodNum = 1 and WeekNum = 1)
set #CalcDate = #StartDate + #i
set #CalcMonth = datepart(mm,#calcdate)
insert into aaGreensPeriodTest(RealDate,GreensYear,GreensPeriod,GreensWeek)
values (#CalcDate,#Year,#Period,#Week)
select #CalcDate as CalcDate, #CalcMonth as CalcMonth
SQL Server 2005 does not support date type without time part.
If your need to get date as a string you can use convert function. For example:
declare #date datetime;
set #date = getdate();
select convert(varchar, #date, 101) -- that will return date in ‘mm/dd/yyyy’ format
If you need a datetime variable without time part for some calculations, you can use an expression below:
declare #date datetime;
set #date = getdate();
select dateadd(dd, datediff(dd, 0, #date), 0)
As per http://msdn.microsoft.com/en-ca/library/ms187928.aspx, you cannot cast float->date directly. It's simply not supporte. But you can cast a datetime->date, so you'll have to double-cast. Or given your example, triple-cast:
CAST(CAST(CAST(#CalcDate AS float) AS datetime) AS date)