How to get the third month of a query without using variables? - sql

I have a query in which I need to get the third month of the given reporting date using SQL and then use it as part of the query. I am able to get all the months but I specifically need to get the third month how would I go about doing that? I know this is fairly easy to do in other languages but is it possible in SQL?
SELECT REPORTING_MONTH, COUNT(*)
FROM database1 AS fb
JOIN (
--derrived core set
SELECT service_no, subscription_id
FROM database2
WHERE REPORTING_MONTH = '2015-04-01' <-- this is the reporting month
) AS c
ON fb.SERVICE_NO = c.service_no
AND fb.subscription_id = c.subscription_id
AND fb.REPORTING_MONTH = '2015-07-01' <-- THIS SHOULD BE THE THIRD MONTH
AND fb.ACTIVE_BASE_IND_NEW = 1
GROUP BY 1
ORDER BY 1
For example if the reporting month is '2015-04-01 I need the variable month to then be '2015-07-01' to be used as part of the query

You don't specify the database you are using. A typical approach would be:
SELECT REPORTING_MONTH, COUNT(*)
FROM database1 fb JOIN
database2 c
ON fb.SERVICE_NO = c.service_no AND
c.REPORTING_MONTH = '2015-04-01' AND
fb.subscription_id = c.subscription_id AND
fb.REPORTING_MONTH = c.reporting_month + interval '3 month' AND
fb.ACTIVE_BASE_IND_NEW = 1
GROUP BY 1
ORDER BY 1;
The exact syntax for + interval '3 month' varies by database.

If the field REPORTING_MONTH is text then you might have to use SUBSTRING (SQL Server) or MID (Others).
If it's a proper date field then perhaps DATEPART(month, fb.REPORTING_MONTH) = 3 will work?
My SQL is a bit rusty but try those functions.

Related

Date automatically where clause - SQL

I have on my DB the dates that I can filter like this:
select *
where
a.y=2021 and a.m=2 and a.d=7
However if I run this query tomorrow I'll have to go there and change manually.
Is there a way to do this automatically as in if I run the query tomorrow I'll get d=8 and the day after d=9 and so on?
I tried to use get date but I get the following error:
SQL Error [6]: Query failed (#20210207_153809_06316_2g4as): line 2:7: Function 'getdate' not registered
I also don't know if that is the right solution. Does anybody know how to fix that?
you can use NOW to get the current date, and use YEAR , MONTH , DAY to get parts of the date
SELECT *
FROM [TABLE]
WHERE a.y=YEAR(NOW()) and a.m=MONTH(NOW()) and a.d=DAY(NOW())
The best solution is to have a date column in your data. Then you can just use:
where datecol = current_date
Or whatever your particular database uses for the current date.
Absent that, you have to split the current date into parts. In Standard SQL, this looks like:
where y = extract(year from current_date) and
m = extract(month from current_date) and
d = extract(day from current_date)
That said, date functions notoriously vary among databases, so the exact syntax depends on your database.
For instance, a common way to write this in SQL Server would be:
where y = year(getdate()) and
m = month(getdate()) and
d = day(getdate())

How to use "groupby" with 7 past days and not "real week" in SQL

I have an SQL pb.
I need to group some bills by "sliding weeks" (my customer need 7 past days on the whole year, so starting on the current day) and I found nothing about it.. I'm quite sure I just don't have good keywords but still it's being 2days I'm searching..
So I have my sql request below which is working with normal WEEK use:
SELECT
WEEK(billing_date) as billed_week
, ROUND(sum(price) * 1.1, 2) as billed_amount
, billing_date as billing_date
FROM bills
JOIN missions m
ON bills.mission_id = m.id
WHERE customer_id = $customer_id
AND status = 2 AND YEAR(billing_date) = YEAR(CURRENT_DATE)
GROUP BY week(billing_date)
By example, is there anyway to update WEEK's function parameters?
You can achieve the results you want by shifting the date passed to WEEK according to the day of the week of today's date. That will result in WEEK returning a value which changes on that day of the week. Given you're using PHP I'm going to assume this is MySQL, in which case you would rewrite your query as:
SELECT
WEEK(billing_date - INTERVAL DAYOFWEEK(billing_date) DAY, 0) as billed_week
, ROUND(sum(price) * 1.1, 2) as billed_amount
, billing_date as billing_date
FROM bills
JOIN missions m
ON bills.mission_id = m.id
WHERE customer_id = $customer_id
AND status = 2 AND YEAR(billing_date) = YEAR(CURRENT_DATE)
GROUP BY WEEK(billing_date - INTERVAL DAYOFWEEK(billing_date) DAY, 0)
Note that I use 0 as the mode parameter to WEEK function so that the result it returns is based on the start of week being Sunday, which is the day of week corresponding to the minimum value returned by DAYOFWEEK.
Note also that as was pointed out by others in the comments, you should not be directly including PHP variables in your query, as that leaves you vulnerable to SQL injection. Instead, use prepared statements with place-holders for the variables you need. For example, something like this (assuming the MySQLi interface with a connection $conn):
$sql = 'SELECT
WEEK(billing_date - INTERVAL DAYOFWEEK(billing_date) DAY, 0) as billed_week
, ROUND(sum(price) * 1.1, 2) as billed_amount
, billing_date as billing_date
FROM bills
JOIN missions m
ON bills.mission_id = m.id
WHERE customer_id = ?
AND status = 2 AND YEAR(billing_date) = YEAR(CURRENT_DATE)
GROUP BY WEEK(billing_date - INTERVAL DAYOFWEEK(billing_date) DAY, 0)';
$stmt = $conn->prepare($sql);
$stmt->bind_param('i', $customer_id);
$stmt->execute();

Query in COGNOS (Report Studio)

I have this follow query;
the objective is to filter this query by day.
I will use this same query, but now a month. How to do?
WITH DATAS(DATA_CALC) AS(
SELECT DATE(#prompt('DataIni')#) AS DATA_CALC FROM SYSIBM.SYSDUMMY1
UNION ALL
SELECT DATA_CALC + 1 DAY FROM DATAS WHERE DATA_CALC < DATE(#prompt('DataFim')#)
)
/* ABERTOS */
SELECT COUNT(*) AS QUANTIDADE, 'ABERTOS' AS TIPO, 1 AS NUM_LINHA, DATE(TRUNC(SOL.DATA_ABERTURA_SOLICITACAO)) AS DATA
FROM VW_SOLICITACAO_DETALHE SOL
INNER JOIN SOLICITACAO SOL_TAB ON (SOL_TAB.ID_SOLICITACAO = SOL.ID_SOLICITACAO)
WHERE SOL.COD_TIPO_SERVICO IN ('MC','OP','SA')
AND SOL_TAB.ID_AREA_COLABORADOR IN (#promptmany('IDArea')#)
AND TRUNC(SOL.DATA_ABERTURA_SOLICITACAO) >= to_date('2014-11-18','YYYY-MM-DD')
AND TRUNC(SOL.DATA_ABERTURA_SOLICITACAO) <= #prompt('DataFim')#
AND ('TODOS' IN (#promptmany('Sistema')#) OR SOL.COD_PRODUTO IN (#promptmany('Sistema')#))
AND DSC_SITUACAO_SOLICITACAO NOT IN ('Desenvolvimento Cancelado')
AND SOL.COD_SOLICITACAO NOT LIKE 'SA%'
GROUP BY TRUNC(SOL.DATA_ABERTURA_SOLICITACAO)
The best solution is to create a Time dimension that includes days and months. This is not easy to plug into Dynamic SQL like you are using above, so you can instead try a work around.
A report studio work around would be to create year and month columns, and group on them:
For year:
extract(year, [datefieldhere])
For month:
extract(month, [datefieldhere])

Invalid Operation On An ANSI DATETIME (Subtracting one timestamp from another in Teradata)

I would like to create a WHERE condition to return results where only 1 day has passed between two timestamps. I tried this:
SELECT * FROM RDMAVWSANDBOX.VwNIMEventFct
INNER JOIN VwNIMUserDim ON VwNIMUserDim.NIM_USER_ID = VwNIMEventFct.NIM_USER_ID
INNER JOIN rdmatblsandbox.TmpNIMSalesForceDB ON TmpNIMSalesForceDB.EMAIL = VwNIMUserDim.USER_EMAIL_ADDRESS
WHERE (CONTRACT_EFFECTIVE_DATE - EVENT_TIMESTAMP) =1
But the result was an error message "Invalid Operation On An ANSI DATETIME value".
I guess that, looking at the code now, Teradata has no way of knowing whether the "1" in "= 1" is a day, hour or year.
How would I select data where only 1 day has passed between CONTRACT_EFFECTIVE_DATE and EVENT_TIMESTAMP?
Same again for 2 days, and 3 days etc?
If both columns are DATEs you can use =1which means one day.
For Timestamps you need to tell what kind of interval you want:
WHERE (CONTRACT_EFFECTIVE_DATE - EVENT_TIMESTAMP) DAY = INTERVAL '1' DAY
But i'm not shure if this is what you really want, what's your definition of 1 day?
Edit:
Based on your comment the best way should be:
WHERE CAST(CONTRACT_EFFECTIVE_DATE AS DATE) - CAST(EVENT_TIMESTAMP AS DATE) = 1
This avoids dealing with INTERVAL arithmetic :-)
Not sure about Teradata, but I think most versions of SQL have built-in date math functions. In MSSQL for instance you could do this:
...
WHERE DATEDIFF(DAY, CONTRACT_EFFECTIVE_DATE, EVENT_TIMESTAMP) = 1
Or if you wanted to make sure 24 hours had passed you could do:
...
WHERE DATEDIFF(HOUR, CONTRACT_EFFECTIVE_DATE, EVENT_TIMESTAMP) = 1
Other SQL's have their own versions of this, and you may have to use 'D' or 'DD' instead of 'DAY' or something (and maybe 'HH' instead of 'HOUR' likewise).

How best store year, month, and day in a MySQL database?

How best store year, month, and day in a MySQL database so that it would be easily retrieved by year, by year-month, by year-month-day combinations?
Let's say you have a table tbl with a column d of type DATE.
All records in 1997:
SELECT * FROM tbl WHERE YEAR(d) = 1997
SELECT * FROM tbl WHERE d BETWEEN '1997-01-01' AND '1997-12-31'
All records in March of 1997:
SELECT * FROM tbl WHERE YEAR(d) = 1997 AND MONTH(d) = 3
SELECT * FROM tbl WHERE d BETWEEN '1997-03-01' AND '1997-03-31'
All records on March 10, 1997:
SELECT * FROM tbl WHERE d = '1997-03-10'
Unless a time will ever be involved, use the DATE data type. You can use functions from there to select portions of the date.
I'd recommend the obvious: use a DATE.
It stores year-month-day with no time (hour-minutes-seconds-etc) component.
Store as date and use built in functions:day(), month() or year() to return the combination you wish.
What's wrong with DATE? As long as you need Y, Y-M, or Y-M-D searches, they should be indexable. The problem with DATE would be if you want all December records across several years, for instance.
This may be related to the problem that archivists have with common date datatypes. Often, you want to be able to encode just the year, or just the year and the month, depending on what information is available, but you want to be able to encode this information in just one datatype. This is a problem which doesn't apply in very many other situations. (In answer to this question in the past, I've had techie types dismiss it as a problem with the data: your data is faulty!)
e.g., in a composer catalogue you are recording the fact that the composer dated a manuscript "January 1951". What can you put in a MySQL DATE field to represent this? "1951-01"? "1951-01-00"? Neither is really valid. Normally you end up encoding years, months and days in separate fields and then having to implement the semantics at application level. This is far from ideal.
If you're doing analytics against a fixed range of dates consider using a date dimension (fancy name for table) and use a foreign key into the date dimension. Check out this link:
http://www.ipcdesigns.com/dim_date/
If you use this date dimension consider how easily it will be to construct queries against any kind of dates you can think of.
SELECT * FROM my_table
JOIN DATE_DIM date on date.PK = my_table.date_FK
WHERE date.day = 30 AND
date.month = 1 AND
date.year = 2010
Or
SELECT * FROM my_table
JOIN DATE_DIM date on date.PK = my_table.date_FK
WHERE date.day_of_week = 1 AND
date.month = 1 AND
date.year = 2010
Or
SELECT *, date.day_of_week_name FROM my_table
JOIN DATE_DIM date on date.PK = my_table.date_FK
WHERE date.is_US_civil_holiday = 1