SQL 13 months transaction and quantity data extract broken down per month - sql

I was reading through a couple of older posts and tried to apply the same logic to my question, I need to extract 13 months of data broken down per month, I would also like to apply the data to relevant headers... any suggestions. Please see code below and error received.
SELECT ST.TXDATE, ST.CODE, ST.QUANTITY
FROM StocTran ST
WHERE ST.TXDATE >= DATEADD(MONTH, -13, CAST(GETDATE() AS DATE))
ORDER BY ST.TXDATE
ERROR: [Elevate Software][DBISAM] DBISAM Engine Error # 11949 SQL
parsing error - Expected end of statement but instead found ( in
SELECT SQL statement at line 3, column 27 Error Code: 11949

DATEADD is a function in MS's TransactSQL for Sql Server. I do not know that DBIsam supports it, and it is not listed in DBIsam's list of supported functions here:
https://www.elevatesoft.com/manual?action=viewtopic&id=dbisam4&product=delphi&version=7&topic=functions
Generally, date functions are not portable across different SQL engines, and from that list, one possibility might be to use the EXTRACT function instead:
The EXTRACT function returns a specific value from a date, time, or timestamp value. The syntax is as follows:
EXTRACT(extract_value
FROM column_reference or expression)
EXTRACT(extract_value,
column_reference or expression)
Use EXTRACT to return the year, month, week, day of week, day, hours, minutes, seconds, or milliseconds from a date, time, or timestamp column. EXTRACT returns the value for the specified element as an integer.
The extract_value parameter may contain any one of the specifiers:
YEAR
MONTH
WEEK
DAYOFWEEK
DAYOFYEAR
DAY
HOUR
MINUTE
SECOND
MSECOND
Even if you are in a hurry, I strngly recommend that you study that page carefully.
UPDATE: From googling dbisam dateadd it looks like Elevate don't have a good answer for an equivalent to DATEADD. One of the hits is this thread:
https://www.sqlservercentral.com/Forums/Topic173627-169-1.aspx
which suggested an alternative way to do it using Delphi's built-in date functions (like IncMonth which I suggested you use in an answer to another q. Basically, you would calculate the start- and end-dates of a range of dates, then convert them to strings to construct a WHERE clause with a column date (from your db) which is equal to or greater than the start date and less or equal to the end date.

Related

Why is the result of datediff year in Firebird too high?

I have question about function datediff in firebird. When I try to diff two dates like 15.12.1999 and 30.06.2000 in sql like this
SELECT
SUM(datediff (YEAR, W.FROM, W.TO)),
SUM(datediff (MONTH, W.FROM, W.TO)),
SUM(datediff (DAY, W.FROM, W.TO))
FROM WORKERS W
WHEN W.ID=1
I get in result 1 year, 6 month and 198 days but it is not true with value years (of course result should be 0) How I have to write my query to get correct result in parameter year? In that link https://firebirdsql.org/refdocs/langrefupd21-intfunc-datediff.html in documentation there is information about this case but there is not how to solve this problem.
The documentation is not very clear, but I'm pretty sure that datediff() is counting the number of boundaries between two dates. (This is how the very similar function in SQL Server works.) Hence, for year, it is counting the number of "Dec 31st/Jan 1st" boundaries. This is explicitly explained in the documentation.
If you want a more accurate count, you can use a smaller increment. The following is pretty close:
(datediff(day, w.from, t.to) / 365.25) as years_diff

Detecting Invalid Dates in Oracle 11g database (ORA-01847 )

I am querying an Oracle 11.2 instance to build a small data mart that includes extracting the date of birth and date of death of people.
Unfortunately the INSERT query (which takes its data from a SELECT) fails due to ORA-01847 (day of month must be between 1 and last day of month).
To find my bad dates I first did:
SELECT extract(day FROM SOME_DT_TM),
extract(month FROM SOME_DT_TM),
COUNT(*)
FROM PERSON
GROUP BY extract(day FROM SOME_DT_TM), extract(month FROM SOME_DT_TM)
ORDER BY COUNT(*) DESC;
It gave me 367 rows, one for each day of the year including NULL and February-29th (leap year). True for the other date column as well, so it looks like the data is fine from a SELECT perspective.
However if I set logging up on my insert
create table registry_new_dates
(some_dob date, some_death_date date);
exec dbms_errlog.create_error_log('SOME_NEW_DATES');
And then run my long insert query:
SELECT some_dob,some_death_date,ora_err_mesg$ FROM ERR$_SOME_NEW_DATES;
I get the following weird results (first 3 rows shown) which makes me think that zip codes have been somehow inserted instead of dates for the 2nd column.
31-DEC-25 35244 "ORA-01847: day of month must be between 1 and last day of month"
13-DEC-33 35244-3402 "ORA-01847: day of month must be between 1 and last day of month"
23-JUN-58 35235 "ORA-01847: day of month must be between 1 and last day of month"
My question is - how do I detect these bad rows (there are 11 apparentlyh) with an SQL statement so I can fix or remove them. Fixing them in the originating table is not an option (no write privileges). I tried using queries like this:
SELECT DECEASED_DT_TM
FROM WH_CLN_PERSON
WHERE DECEASED_DT_TM LIKE '35%'
AND rownum<3;
But it did not find the offending rows.
Not sure if you are still actively researching this (or if you got an answer already).
To find the rows with the bad data, can't you instead select the DOB and the date of death, and express the WHERE clause in terms of DOB - like so:
...WHERE some_dob = to_date('31-DEC-25')
? After you find those rows, you may want to do another query on just one or two of those rows, including a calculated column: dump(date of death). Then post that. We can learn a lot from the dump - the internal representation of the so-called "date" (which may very well be a ZIP code instead). With that in hand we may be able to figure out what's stored, and how to hunt for it.

sqlalchemy select by date column only x newset days

suppose I have a table MyTable with a column some_date (date type of course) and I want to select the newest 3 months data (or x days).
What is the best way to achieve this?
Please notice that the date should not be measured from today but rather from the date range in the table (which might be older then today)
I need to find the maximum date and compare it to each row - if the difference is less than x days, return it.
All of this should be done with sqlalchemy and without loading the entire table.
What is the best way of doing it? must I have a subquery to find the maximum date? How do I select last X days?
Any help is appreciated.
EDIT:
The following query works in Oracle but seems inefficient (is max calculated for each row?) and I don't think that it'll work for all dialects:
select * from my_table where (select max(some_date) from my_table) - some_date < 10
You can do this in a single query and without resorting to creating datediff.
Here is an example I used for getting everything in the past day:
one_day = timedelta(hours=24)
one_day_ago = datetime.now() - one_day
Message.query.filter(Message.created > one_day_ago).all()
You can adapt the timedelta to whatever time range you are interested in.
UPDATE
Upon re-reading your question it looks like I failed to take into account the fact that you want to compare two dates which are in the database rather than today's day. I'm pretty sure that this sort of behavior is going to be database specific. In Postgres, you can use straightforward arithmetic.
Operations with DATEs
1. The difference between two DATES is always an INTEGER, representing the number of DAYS difference
DATE '1999-12-30' - DATE '1999-12-11' = INTEGER 19
You may add or subtract an INTEGER to a DATE to produce another DATE
DATE '1999-12-11' + INTEGER 19 = DATE '1999-12-30'
You're probably using timestamps if you are storing dates in postgres. Doing math with timestamps produces an interval object. Sqlalachemy works with timedeltas as a representation of intervals. So you could do something like:
one_day = timedelta(hours=24)
Model.query.join(ModelB, Model.created - ModelB.created < interval)
I haven't tested this exactly, but I've done things like this and they have worked.
I ended up doing two selects - one to get the max date and another to get the data
using the datediff recipe from this thread I added a datediff function and using the query q = session.query(MyTable).filter(datediff(max_date, some_date) < 10)
I still don't think this is the best way, but untill someone proves me wrong, it will have to do...

adding months to a date SQL

I am trying to add months to an existing date in SQL. The new column displayed will have a followup column instead of a days column. Im getting an error in the select statement.can u help?
Create table auctions(
item varchar2(50),
datebought date,
datesold date,
days number
);
Insert into auctions values (‘Radio’,’12-MAY-2001’,’21-MAY-2001’,9);
Select item,datebought,datesold,ADD MONTHS(datesold,3)”followup” from auctions;
Your usage of the add_months() function is incorrect. It's not two words, it's just one (with an underscore)
add_months(datesold, 1)
note the underscore _ between ADD and MONTHS. It's function call not an operator.
Alternatively you could use:
datesold + INTERVAL '1' month
Although it's worth noting that the arithmetics with intervals is limited (if not broken) because it simply "increments" the month value of the date value. That can lead to invalid dates (e.g. from January to February). Although this is documented behaviour (see below links) I consider this a bug (the SQL standard requires those operations to "Arithmetic obey the natural rules associated with dates and times and yield valid datetime or interval results according to the Gregorian calendar")
See the manual for details:
http://docs.oracle.com/cd/E11882_01/server.112/e26088/functions011.htm#i76717
http://docs.oracle.com/cd/E11882_01/server.112/e26088/sql_elements001.htm#i48042
Another thing:
I am trying to add months to an existing date in SQL.
Then why are you using an INSERT statement? To change the data of existing rows you should use UPDATE. So it seems what you are really after is something like this:
update auctions
set datesold = add_months(datesold, 1)
where item = 'Radio';
Your SQL has typographical quotation marks, not standard ones. E.g. ’ is not the same as '. Instead of delimiting a string value, those quotes become part of the value, at least for the particular SQL I have here to test with.
If this doesn't fix your problem, try posting the error you're getting in your question. Magical debugging isn't possible.
This can be used to add months to a date in SQL:
select DATEADD(mm,1,getdate())
This might be a useful link.

Getting the range in SQL when given between

I am wondering if it's possible (without actually parsing the given string) to get the actual range (in terms of days, minutes or seconds) that is specified when you have an SQL statement like
[select 'x'
from dual
where date between to_date('20111113152049')
and to_date('20120113152049')]
I am working on a query where I'm given a string in the form of
"between to_date(A) and to_date(B)"
and would like to get that value in days to compare to a policy we let the user set so they don't enter a date range longer than say a week.
Assuming you're looking for a theoretical answer (that is: don't take this into production) this could work:
Prerequistes:
have three tables: days_seq(day_seq), month_seq(mth_seq) and year_seq(yr_seq)
days has the numbers 1...31, month 1..12, years 2011....?
Use te following query (I used access because I don't have proper RDBMS available here, keep in mind that MS-ACCESS/JET is forgiving in the use of the Dateserial function, that is, it doesn't break when you ask the dateserial for february, 30th, 2012)
SELECT Max(DateSerial(
[year_seq]![yr_seq]
,[month_seq]![mth_seq]
, [days_seq]![day_seq]))
-
Min(DateSerial(
[year_seq]![yr_seq]
,[month_seq]![mth_seq]
,[days_seq]![day_seq])) AS days
FROM days_seq, month_seq, year_seq
WHERE DateSerial(
[year_seq]![yr_seq]
,[month_seq]![mth_seq]
,[days_seq]![day_seq])
BETWEEN #2012-02-1# AND #2012-02-28#
The query basically produces a carthesian product of three tables which generates all possible days in months, months in a year for as many years as you have in the years table.
Bonus:
You could off-course generate a permanent Calendar table as X-Zero suggests.
table calendar([date])
INSERT INTO calendar
SELECT DISTINCT DateSerial(
[year_seq]![yr_seq]
,[month_seq]![mth_seq]
, [days_seq]![day_seq]))
FROM days_seq, month_seq, year_seq
You still have to pick your start year and your end year wisely. According to the Maya's an enddate of december 21st, 2012 will do.