Where condition based on month and year - sql-server

i have the following code:
select COUNT(STL.ITEID)
from STORETRADELINES STL
left join FINTRADE FT ON STL.FTRID=FT.ID
where RIGHT(CONVERT(datetime, FT.FTRDATE, 3), 5) < RIGHT(CONVERT(datetime, GETDATE(), 3), 5)
and FT.FTRDATE > CONVERT(datetime,'01.01.2017',103)
I want to select all the documents that fall between 01.01.2017 and 30.04.2017 (always, the last day of the previous month).
Seem's that this way is not good, because is returning all the docs from 01.01 until today.
Where am i wrong ? Btw, i use sql server 2008.
Thank you

The problem is, you're doing string comparisons. Use date comparisons instead:
select COUNT(STL.ITEID)
from STORETRADELINES STL
left join FINTRADE FT ON STL.FTRID=FT.ID
where FT.FTRDATE < DATEADD(month,DATEDIFF(month,0,GETDATE()),0)
and FT.FTRDATE >= '20170101'
Here, the DATEADD/DATEDIFF pair of calls are rounding the current date down to the start of the current month.
You can use a similar DATEADD/DATEDIFF pair for your start-of-period condition, using year instead of month if you want this query to be generic for any current year
The reason you're "stringly-typed" code doesn't work is that your CONVERT calls are converting datetime values to datetime. The style parameter is ignored here since datetimes don't have a format. You then get an uncontrolled implicit conversion of the datetimes into varchar so that RIGHT can work, and it's that conversion that you should have tried to control.
As it is, this:
select RIGHT(CONVERT(datetime, GETDATE(), 3), 5)
Generates:
:50AM
Which you can hopefully see is nothing like what you wanted.

dateadd(mm,datediff(mm, 0 , current_timestamp),0) will return the first day of current month.
Your query could be
SELECT COUNT(STL.ITEID)
FROM STORETRADELINES STL
left join FINTRADE FT ON STL.FTRID=FT.ID
where
FT.FTRDATE >= '2017-01-01' AND FT.FTRDATE < dateadd(mm,datediff(mm, 0 , current_timestamp),0)

Related

SQL: Fill NULL values in time series with closest preceding existing value [duplicate]

This question already has answers here:
How to get Previous Value for Null Values
(5 answers)
Closed 2 years ago.
I created the following statement:
SELECT
convert(varchar, cal.[Datum], 104) as Datum
, snb.[Kurs] as FX_CHF_EUR_SNB
FROM [DM_MAH].[dbo].[SNB_Kurs] snb
RIGHT JOIN [dbo].[Dim_Kalender] cal
ON snb.Datum = cal.Datum
WHERE cal.Datum >= '2019-05-14' and cal.Datum <= GETDATE()
Order by cal.Datum desc
Which gives me the following result:
Datum FX_CHF_EUR_SNB
12.05.2020 1.051500
11.05.2020 1.052300
10.05.2020 NULL
09.05.2020 NULL
08.05.2020 1.052800
07.05.2020 1.053200
06.05.2020 1.052800
05.05.2020 1.052500
04.05.2020 1.054700
03.05.2020 NULL
02.05.2020 NULL
01.05.2020 NULL
30.04.2020 1.056900
29.04.2020 1.056000
As you can see there are NULL values for different dates in the time series. This is expected because where I get the data from they don't have values for every day of the year. For my purpose I need the completed time series with every day of the year though, which is why I joined it with a calendar table. So far so good.
What I am not able to do, is, fill the NULL values with the closest preceding existing value of the time series. So here an example of what I want to achieve with the given data:
Datum FX_CHF_EUR_SNB
12.05.2020 1.051500
11.05.2020 1.052300
10.05.2020 **1.052800**
09.05.2020 **1.052800**
08.05.2020 1.052800
so the values for 09.05.2020 and 10.05.2020 in this case should be copied from the 08.05.2020
Would be glad if anyone knew how to solve this.
One approach uses a correlated subquery to choose the correct non NULL value to report from the SNB_Kurs table:
SELECT
CONVERT(varchar, cal.[Datum], 104) AS Datum,
(SELECT TOP 1 snb.[Kurs] FROM [DM_MAH].[dbo].[SNB_Kurs] snb
WHERE snb.Datum <= cal.Datum AND snb.Datum IS NOT NULL
ORDER BY snb.Datum DESC) AS FX_CHF_EUR_SNB
FROM [dbo].[Dim_Kalender] cal
WHERE cal.Datum >= '2019-05-14' AND cal.Datum <= GETDATE()
ORDER BY cal.Datum DESC;

Alternative to cursor when applying a list of values to a where clause?

What's an alternative to getting a distinct number of dates, say all the dates for September:
9/1/2016
9/2/2016
9/3/2016
and apply each value to a query. Say something like:
Select GuitarId,GuitarBrand
From GuitarSales
Where GuitarDate = #date
I don't want to use a cursor, is there an alternative to doing this?
I tried a CTE but even then I'd have to apply the cursor for each date.
If you want all the dates for a month you can use
Select GuitarId,GuitarBrand
From GuitarSales
Where month(GuitarDate) = 9
and year(GuitarDate) = 2016;
If I understand you correctly, you need a list of all dates in September. This is a quick solution to get a gapless list of all days in September: In your query you can use this as source and LEFT JOIN your actual data.
WITH RunningNumbers AS
(
SELECT TOP(30) ROW_NUMBER() OVER(ORDER BY (SELECT NULL))-1 AS Nr
FROM sys.objects
)
SELECT {d'2016-09-01'}+Nr AS RunningDate
FROM RunningNumbers
There are many examples, how you can create a tally table on the fly. Small numbers (like 30 in this example) can be taken easily from any table with sufficient rows.
If you need this more often you might think about a Numbers-Table
a related question: https://stackoverflow.com/a/39387790/5089204
create a persitant numbers table with a lot of usefull side data: https://stackoverflow.com/a/32474751/5089204
Assuming you have an index on GuitarDate here is a way you can create a SARGable where predicate so you can still leverage the speed of using an index seek.
declare #date datetime = '2016-09-10' --just to demonstrate starting with September 10, 2016
select gs.GuitarId
, gs.GuitarBrand
From GuitarSales gs
where gs.GuitarDate >= dateadd(month, datediff(month, 0, #date), 0) --beginning of the month for #date
and gs.GuitarDate < dateadd(month, datediff(month, 0, #date) + 1, 0) --beginning of next month

Select the last 7 days of each month

I am using SQL Server 2008. I'm looking to bring back only the last 7 calendar days of each month, how would I go about doing this.
Thanks
assuming field called logtime, get the range with
....where logtime BETWEEN dateadd(month,month(logtime),dateadd(year, year(logtime) - 1900,0)) - 7
AND
dateadd(month,month(logtime),dateadd(year, year(logtime) - 1900,0)) - 1;
you also need to check that 'logtime' (replaced by your field name) is in the range of dates you are also selecting from e.g ...AND(YEAR(logtime)) = 2016 ..for example
Try this
SELECT
*
FROM
Payments P
WHERE
P.PaymentDay < (SELECT DATEADD(month, ((YEAR(P.PaymentDay) - 1900) * 12) + MONTH(P.PaymentDay), -1)) AND -- Last day of current year-month
P.PaymentDay > (SELECT DATEADD(month, ((YEAR(P.PaymentDay) - 1900) * 12) + MONTH(P.PaymentDay), -7)) -- Last 7. day of current year-month
Some specific examples and direction would help. If you just want rows where, say columnA contains a date that falls within the last 7 days of it's respective month, then you can simply say:
WHERE month(columnA) != month(dateadd(day,7,columnA))
I.e. it asks the question, "given a date, A, does the date 7 days later fall in a different month?"
Note that neither this query nor those include in other answers is able to make use of indexes on this column (since we're using it as an input to a calculation), which is a shame.
Try this:
--DAY(DATE) as day_of_month from day_master table.
select
a.day_id,a.day_of_month
from day_master a LEFT JOIN (select max(day_of_month) as 'max_day_of_month',day_id,month_no,year_no from day_master group by month_no,year_no)b ON b.month_no=a.month_no and a.year_no=b.year_no
where (b.max_day_of_month-a.day_of_month)<7 and a.month_no=11 and a.year_no=2017
GROUP BY a.month_no,a.year_no,a.day_id;

Access SQL: How to select dates after today if current year, else select all dates

Im working on a query where if the records in a table are from the current year, i need only to select records whose day and month are equal or greater than the current date. Otherwise (if the year is greater) I need to select all dates.
I was thinking of using the iif function or conditions on the where clause but im not close at at all.
For example
SELECT IFF(YEAR(FECHAPAGO) = YEAR(DATE()), MONTO WHERE MONTH(FECHAPAGO) >= MONTH(DATE), MONTO) FROM CUPONES
or
SELECT MONTO FROM CUPONES WHERE IF YEAR(FECHAPAGO) = YEAR(DATE()) ...
I apologize if im not being clear enough but im having trouble putting it to words. If any clarification is needed Ill be happy to rephrase my question.
Thanks in advance
You can do it with straight logic;
select monto from cupones where (year(fechapago) = year(date() and (month(fechapago) > month(date()) or (month(fechapago) == month(date() and day(fechapago) > day(date()))( or (year(fechapago()) > year(date()))

SQL Server datetime LIKE select?

in MySQL
select * from record where register_date like '2009-10-10%'
What is the syntax in SQL Server?
You could use the DATEPART() function
SELECT * FROM record
WHERE (DATEPART(yy, register_date) = 2009
AND DATEPART(mm, register_date) = 10
AND DATEPART(dd, register_date) = 10)
I find this way easy to read, as it ignores the time component, and you don't have to use the next day's date to restrict your selection. You can go to greater or lesser granularity by adding extra clauses, using the appropriate DatePart code, e.g.
AND DATEPART(hh, register_date) = 12)
to get records made between 12 and 1.
Consult the MSDN DATEPART docs for the full list of valid arguments.
There's no direct support for LIKE operator against DATETIME variables, but you can always cast the DATETIME to a VARCHAR:
SELECT (list of fields) FROM YourTable
WHERE CONVERT(VARCHAR(25), register_date, 126) LIKE '2009-10-10%'
Check the MSDN docs for a complete list of available "styles" in the CONVERT function.
Marc
If you do that, you are forcing it to do a string conversion. It would be better to build a start/end date range, and use:
declare #start datetime, #end datetime
select #start = '2009-10-10', #end = '2009-11-10'
select * from record where register_date >= #start
and register_date < #end
This will allow it to use the index (if there is one on register_date), rather than a table scan.
You can use CONVERT to get the date in text form. If you convert it to a varchar(10), you can use = instead of like:
select *
from record
where CONVERT(VARCHAR(10),register_date,120) = '2009-10-10'
Or you can use an upper and lower boundary date, with the added advantage that it could make use of an index:
select *
from record
where '2009-10-10' <= register_date
and register_date < '2009-10-11'
Unfortunately, It is not possible to compare datetime towards varchar using 'LIKE'
But the desired output is possible in another way.
select * from record where datediff(dd,[record].[register_date],'2009-10-10')=0
You can also use convert to make the date searchable using LIKE. For example,
select convert(VARCHAR(40),create_date,121) , * from sys.objects where convert(VARCHAR(40),create_date,121) LIKE '%17:34%'
Try this
SELECT top 10 * from record WHERE IsActive = 1
and CONVERT(VARCHAR, register_date, 120) LIKE '2020-01%'
I am a little late to this thread but in fact there is direct support for the like operator in MS SQL server.
As documented in LIKE help if the datatype is not a string it is attempted to convert it to a string. And as documented in cast\convert documentation:
default datetime conversion to string is type 0 (,100) which is mon dd
yyyy hh:miAM (or PM).
If you have a date like this in the DB:
2015-06-01 11:52:59.057
and you do queries like this:
select * from wws_invoice where invdate like 'Jun%'
select * from wws_invoice where invdate like 'Jun 1%'
select * from wws_invoice where invdate like 'Jun 1 %'
select * from wws_invoice where invdate like 'Jun 1 2015:%'
select * from wws_invoice where invdate like 'Jun ? 2015%'
...
select * from wws_invoice where invdate like 'Jun 1 2015 11:52AM'
you get that row.
However, this date format suggests that it is a DateTime2, then documentation says:
21 or 121 -- ODBC canonical (with milliseconds) default for time,
date, datetime2, and datetimeoffset. -- yyyy-mm-dd hh:mi:ss.mmm(24h)
That makes it easier and you can use:
select * from wws_invoice where invdate like '2015-06-01%'
and get the invoice record. Here is a demo code:
DECLARE #myDates TABLE (myDate DATETIME2);
INSERT INTO #myDates (myDate)
VALUES
('2015-06-01 11:52:59.057'),
('2015-06-01 11:52:59.054'),
('2015-06-01 13:52:59.057'),
('2015-06-01 14:52:59.057');
SELECT * FROM #myDates WHERE myDate LIKE '2015-06-01%';
SELECT * FROM #myDates WHERE myDate LIKE '2015-06-01 11%';
SELECT * FROM #myDates WHERE myDate LIKE '2015-06-01 11:52:59%';
SELECT * FROM #myDates WHERE myDate LIKE '2015-06-01 11:52:59.054%';
Doing datetime searches in SQL server without any conversion to string has always been problematic. Getting each date part is an overkill (which unlikely would use an index). Probably a better way when you don't use string conversion would be to use range checks. ie:
select * from record
where register_date >= '20091010' and register_date < '20091011';
The LIKE operator does not work with date parts like month or date but the DATEPART operator does.
Command to find out all accounts whose Open Date was on the 1st:
SELECT *
FROM Account
WHERE DATEPART(DAY, CAST(OpenDt AS DATE)) = 1`
*CASTING OpenDt because it's value is in DATETIME and not just DATE.
There is a very flaky coverage of the LIKE operator for dates in SQL Server. It only works using American date format. As an example you could try:
... WHERE register_date LIKE 'oct 10 2009%'
I've tested this in SQL Server 2005 and it works, but you'll really need to try different combinations. Odd things I have noticed are:
You only seem to get all or nothing for different sub fields within the date, for instance, if you search for 'apr 2%' you only get anything in the 20th's - it omits 2nd's.
Using a single underscore '_' to represent a single (wildcard) character does not wholly work, for instance, WHERE mydate LIKE 'oct _ 2010%' will not return all dates before the 10th - it returns nothing at all, in fact!
The format is rigid American: 'mmm dd yyyy hh:mm'
I have found it difficult to nail down a process for LIKEing seconds, so if anyone wants to take this a bit further, be my guest!
Hope this helps.
I solved my problem that way. Thank you for suggestions for improvements.
Example in C#.
string dd, mm, aa, trc, data;
dd = nData.Text.Substring(0, 2);
mm = nData.Text.Substring(3, 2);
aa = nData.Text.Substring(6, 4);
trc = "-";
data = aa + trc + mm + trc + dd;
"Select * From bdPedidos Where Data Like '%" + data + "%'";
I realise this an old question, but a lot of the answers here don't give a SARGable answer here, nor cover parmetrisation.
First off, you are far better off using >= and < logic. For the date you want, then that would look like this:
SELECT {Your Columns}
FROM dbo.record
WHERE register_date >= '20091010'
AND register_date < '20091011';
This'll include every time value on 2009-10-10, including the stroke of midnight on the day, and a nanosecond prior to 2009-10-11.
Often, however, you'll be parametrising your query, so instead what you can do is use DATEADD to add a day to the second clause:
DECLARE #DateParam date = '20091010';
SELECT {Your Columns}
FROM dbo.record
WHERE register_date >= #DateParam
AND register_date < DATEADD(DAY,1,#DateParam);
This maintains SARGability and means that any indexes on register_date can be used.

Resources