sql Countrows between date from other table and current_date - sql

All,
To be honest I used to work with Power bi without knowing SQL, so I am learning things backwards.
I started learning SQL two weeks ago for my current (new role) at work.
So probably it is just a simple rookie mistake.
In this case I have 2 tables
events and marketingprofiles
In Table 1 (events) I have columns named
pk_eventtype_id (Which I want to count)
eve.starting (which is the date of the interview)
From the other Table 2 (marketingprofiles) I need the
marketinglivedate (as the new date to count from) Till current_date.
Both tables have a relationship column called mar.pk_marketingprofile_id and eve.marketingprofile_id
I am trying to count the number of interviews someone had in a certain period.
Tried it like this with a sub query, but receive an error at the
ERROR: syntax error at or near "(" LINE 8: (SELECT count(*)
SELECT
eve.femarketingname,
eve.starting,
eve.ending,
eve.pk_event_id,
COUNT(eve.pk_event_id) AS num_int
(SELECT count(*)
FROM marketingprofiles mar
where mar.marketinglivedate >= eve.starting
AND current_date <= eve.ending) AS num_int_by_MLD
FROM events eve
GROUP BY eve.femarketingname,
eve.starting,
eve.ending,
eve.pk_event_id
So I tried with an other method,But here i get the error:
ERROR: operator does not exist: integer >= timestamp with time
zone LINE 8: Where pk_event_id BETWEEN eve.starting and
current_date
Select
*,
Count(pk_event_id)
From
Events eve
Left join marketingprofiles mar
On eve.starting = mar.marketinglivedate
Where pk_event_id BETWEEN eve.starting and current_date
Group by femarketingname

Related

Sybase IQ - Pull the last 30 days of data where the most recent date is not today

Objective: Pull the last 30 days of data from a table that has a variable end date
Background: I have a table that contains purchase information but this table is only updated every two weeks therefore there's a lag in the data. Some day it can be 14 days behind and others 13 or 15 days behind.
My table contains a DATE_KEY column which joins to the DATE_DIM table on this key which is where I pull my date field from. I would use GETDATE or CURRENT_DATE but this is not appropriate in my case due to the lag.
I am using Sybase IQ and I believe I can't use a select statements in the where clause to compare dates, I got the following error:
Feature, scalar value subquery (at line 63) outside of a top level SELECT list, is not supported.
This is what I was trying to do
WHERE
TIME.[DAY] >= DATEADD(dd,-30,( SELECT
MAX([TIME1].[DAY])
FROM DB.DATE_DIM TIME1
JOIN DB.PURCHASES PURC
ON TIME1.KEY = PURC.KEY))
How can I pull the most recent 30 days of data given the constraints above?
According to the Sybase IQ documentation, you can use a comparison to a subquery, hence you could add a join to the DATE_DIM to the main FROM clause, and then compare that to a subquery similar to yours, just with the DATEADD moved into it. In the following code, I assume the alias for DATE_DIM in the main FROM clause is TIME0.
WHERE
TIME0.[DAY] >= (SELECT DATEADD(dd,-30, MAX([TIME1].[DAY]))
FROM DB.DATE_DIM TIME1
JOIN DB.PURCHASES PURC
ON TIME1.KEY = PURC.KEY
)

Query for Age calculation and Date comparison inconsistent

I'm doing some counts to validate a table XXX, I designed 2 queries to calculate people younger than 18 years.
The query i'm using is the following:
select count(distinct user.id) from user
left join sometable on sometable.id = user.someTableId
left join anotherTable on sometable.anotherTableId = anotherTable.id
where (sometable.id = 'x' or user.public = true)
AND (DATE_PART('year', age(current_date, user.birthdate)) >= 0 and DATE_PART('year', age(current_date, user.birthdate)) <= 18);
This query is giving 5000 counts (Fake result)
but this query that is supposed to do the same:
select count(distinct user.id) from user
left join sometable on sometable.id = user.someTableId
left join anotherTable on sometable.anotherTableId = anotherTable.id
where (sometable.id = 'x' or user.public = true)
and (user.birthdate between '2002-08-26' and current_date)
SIDE NOTE: date '2002-08-26' is because today is 2020-08-26, so I subtracted 18 years from today's date.
is giving me a different count from the first one. (This last one, is giving the correct one, since is the same that I've in another nosql database)
I would like to know what's the difference in the queries or why the counts are different.
Thanks in advance.
In your first query, you are including everyone who has not yet turned 19.
In your second query, you are excluding a bunch of 18 year old's who were born prior to 2002-08-26. For example, someone born on 2002-04-12 is still 18 years old. She won't turn 19 until 2021-04-12.
Easiest way to write in postgres is this, which provides same results as your first query:
where extract(year from age(now(), birthdate)) <= 18
If you really want to use the format of your 2nd query, then change your line to:
where (birth_date between '2001-08-27' and current_date)

DB2 Error. Inserting to a table through select query

I am tryin to insert some data to a table usin a query that uses tables and subquery. The subquery is where the case clause is used, and a I get the error : ERROR [HY000] [IBM][Controlador ODBC de iSeries Access][DB2 UDB]SQL0420 - The CAST argument character is not valid.
I only get this error when I run the insert command. When I run the select command there are no errors. this is the query
insert into qlib.table
select a.fieldkey, a.field2, ifnull(n.firstdate,0) as firstdate, ifnull(n.lastdate,0) as lastdate, n.totamount, n.timespan
from mainlib.tablea a
left join (select b.fieldkey, MIN(rtrim(b.year)||'-'||case when b.month<10 then '0'||b.month else rtrim(b.month)end) as firstdate,
MAX(rtrim(b.year)||'-'||case when b.month<10 then '0'||b.month else rtrim(b.month) end) as lastdate, sum(b.amount) as totamount,
cast(count(b.year)/12 as char(2))||' Years '||cast(count(b.year)-(count(b.year)/12)*12 as char(2))||' Months' as timespan
from mainlib.tableb b
group by b.fieldkey) n on n.fieldkey = a.fieldkey
Tableb contains monthly savings ok. The subquery returns the first year-month of saving, the last year-month, the total amount, and the years and months span of saving monthly, under the assumption that every month there is a saving/deposit, for each fieldkey
Is there anything wrong with the cast clause of the subquery. Again I only get error when I am trying to insert to qlib.table using the select command.
A few things might clean up your query:
case when b.month<10 then '0'||b.month else rtrim(b.month)end can be replaced with
VARCHAR_FORMAT(b.month,'00')
cast(count(b.year)/12 as char(2))||' Years '||cast(count(b.year)-(count(b.year)/12)*12 as char(2))||' Months' rewritten as
VARCHAR_FORMAT(count(b.year)/12,'99')||' Years '||VARCHAR_FORMAT(count(b.year)-(count(b.year)/12)*12,'99')||' Months'

SQL - All appointments to current day

I have following query and I get followig error:
Only one expression can be specified in the select list when the subquery is not introduced with EXISTS
I want that dodate is less than date today so if i have appointments which isn't marked as "done" so query will list all of my appointments to current day.
select
dodate, regdate,header,starttime,stoptime,userid,custid,objid,infoid,aname
from fkms.appointment
where
done=0 and del=0
and dodate > (SELECT dodate,
DATEADD(d,dodate - 2440587,'1970-01-01'),
ts,
DATEADD(s,ts,'19700101 01:0:00:000')
FROM fkms.appointment)
and userid='da'
Any tips?
Your query is illegal as the inner SELECT returns more than one value. Change it to:
select
dodate, regdate,header,starttime,stoptime,userid,custid,objid,infoid,aname
from fkms.appointment
where done = 0
and del = 0
and dodate > GETDATE()
and userid ='da';
NOTE: GETDATE() is SQL-SERVER function. IN Oracle you have NOW() and other DBMSs similar functions. Find out which one you need.

Calculating working days including holidays between dates without a calendar table in oracle SQL

Okay, so I've done quite a lot of reading on the possibility of emulating the networkdays function of excel in sql, and have come to the conclusion that by far the easiest solution is to have a calendar table which will flag working days or non working days. However, due to circumstances out of my control, we don't have access to such a luxury and it's unlikely that we will any time in the near future.
Currently I have managed to bodge together what is undoubtedly a horrible ineffecient query in SQL that does work - the catch is, it will only work for a single client record at a time.
SELECT O_ASSESSMENTS.ASM_ID,
O_ASSESSMENTS.ASM_START_DATE,
O_ASSESSMENTS.ASM_END_DATE,
sum(CASE
When TO_CHAR(O_ASSESSMENTS.ASM_START_DATE + rownum -1,'Day')
= 'Sunday ' THEN 0
When TO_CHAR(O_ASSESSMENTS.ASM_START_DATE + rownum -1,'Day')
= 'Saturday ' THEN 0
WHEN O_ASSESSMENTS.ASM_START_DATE + rownum - 1
IN ('03-01-2000','21-04-2000','24-04-2000','01-05-2000','29-05-2000','28-08-2000','25-12-2000','26-12-2000','01-01-2001','13-04-2001','16-04-2001','07-05-2001','28-05-2001','27-08-2001','25-12-2001','26-12-2001','01-01-2002','29-03-2002','01-04-2002','06-04-2002','03-06-2002','04-06-2002','26-08-2002','25-12-2002','26-12-2002','01-01-2003','18-04-2003','21-04-2003','05-05-2003','26-05-2003','25-08-2003','25-12-2003','26-12-2003','01-01-2004','09-04-2004','12-04-2004','03-05-2004','31-05-2004','30-08-2004','25-12-2004','26-12-2004','27-12-2004','28-12-2004','01-01-2005','03-01-2005','25-03-2005','28-03-2005','02-05-2005','30-05-2005','29-08-2005','27-12-2005','28-12-2005','02-01-2006','14-04-2006','17-04-2006','01-05-2006','29-05-2006','28-08-2006','25-12-2006','26-12-2006','02-01-2007','06-04-2007','09-04-2007','07-05-2007','28-05-2007','27-08-2007','25-12-2007','26-12-2007','01-01-2008','21-03-2008','24-03-2008','05-05-2008','26-05-2008','25-08-2008','25-12-2008','26-12-2008','01-01-2009','10-04-2009','13-04-2009','04-05-2009','25-05-2009','31-08-2009','25-12-2009','28-12-2009','01-01-2010','02-04-2010','05-04-2010','03-05-2010','31-05-2010','30-08-2010','24-12-2010','27-12-2010','28-12-2010','31-12-2010','03-01-2011','22-04-2011','25-04-2011','29-04-2011','02-05-2011','30-05-2011','29-08-2011','26-12-2011','27-12-2011')
THEN 0
ELSE 1
END)-1 AS Week_Day
From O_ASSESSMENTS,
ALL_OBJECTS
WHERE O_ASSESSMENTS.ASM_QSA_ID IN ('TYPE1')
AND O_ASSESSMENTS.ASM_END_DATE >= '01/01/2012'
AND O_ASSESSMENTS.ASM_ID = 'A00000'
AND ROWNUM <= O_ASSESSMENTS.ASM_END_DATE-O_ASSESSMENTS.ASM_START_DATE+1
GROUP BY
O_ASSESSMENTS.ASM_ID,
O_ASSESSMENTS.ASM_START_DATE,
O_ASSESSMENTS.ASM_END_DATE
Basically, I'm wondering if a) I should stop wasting my time on this or b) is it possible to get this to work for multiple clients? Any pointers appreciated thanks!
Edit: Further clarification - I already work out timescales using excel, but it would be ideal if we could do it in the report as the report in question is something that we would like end users to be able to run without any further manipulation.
Edit:
MarkBannister's answer works perfectly albeit slowly (though I had expected as much given it's not the preferred solution) - the challenge now lies in me integrating this into an existing report!
with
calendar_cte as (select
to_date('01-01-2000')+level-1 calendar_date,
case when to_char(to_date('01-01-2000')+level-1, 'day') in ('sunday ','saturday ') then 0 when to_date('01-01-2000')+level-1 in ('03-01-2000','21-04-2000','24-04-2000','01-05-2000','29-05-2000','28-08-2000','25-12-2000','26-12-2000','01-01-2001','13-04-2001','16-04-2001','07-05-2001','28-05-2001','27-08-2001','25-12-2001','26-12-2001','01-01-2002','29-03-2002','01-04-2002','06-04-2002','03-06-2002','04-06-2002','26-08-2002','25-12-2002','26-12-2002','01-01-2003','18-04-2003','21-04-2003','05-05-2003','26-05-2003','25-08-2003','25-12-2003','26-12-2003','01-01-2004','09-04-2004','12-04-2004','03-05-2004','31-05-2004','30-08-2004','25-12-2004','26-12-2004','27-12-2004','28-12-2004','01-01-2005','03-01-2005','25-03-2005','28-03-2005','02-05-2005','30-05-2005','29-08-2005','27-12-2005','28-12-2005','02-01-2006','14-04-2006','17-04-2006','01-05-2006','29-05-2006','28-08-2006','25-12-2006','26-12-2006','02-01-2007','06-04-2007','09-04-2007','07-05-2007','28-05-2007','27-08-2007','25-12-2007','26-12-2007','01-01-2008','21-03-2008','24-03-2008','05-05-2008','26-05-2008','25-08-2008','25-12-2008','26-12-2008','01-01-2009','10-04-2009','13-04-2009','04-05-2009','25-05-2009','31-08-2009','25-12-2009','28-12-2009','01-01-2010','02-04-2010','05-04-2010','03-05-2010','31-05-2010','30-08-2010','24-12-2010','27-12-2010','28-12-2010','31-12-2010','03-01-2011','22-04-2011','25-04-2011','29-04-2011','02-05-2011','30-05-2011','29-08-2011','26-12-2011','27-12-2011','01-01-2012','02-01-2012') then 0 else 1 end working_day
from dual
connect by level <= 1825 + sysdate - to_date('01-01-2000') )
SELECT
a.ASM_ID,
a.ASM_START_DATE,
a.ASM_END_DATE,
sum(c.working_day)-1 AS Week_Day
From
O_ASSESSMENTS a
join calendar_cte c
on c.calendar_date between a.ASM_START_DATE and a.ASM_END_DATE
WHERE a.ASM_QSA_ID IN ('TYPE1')
and a.ASM_END_DATE >= '01/01/2012'
GROUP BY
a.ASM_ID,
a.ASM_START_DATE,
a.ASM_END_DATE
There are a few ways to do this. Perhaps the simplest might be to create a CTE that produces a virtual calendar table, based on Oracle's connect by syntax, and then join it to the Assesments table, like so:
with calendar_cte as (
select to_date('01-01-2000')+level-1 calendar_date,
case when to_char(to_date('01-01-2000')+level-1, 'Day')
in ('Sunday ','Saturday ') then 0
when to_date('01-01-2000')+level-1
in ('03-01-2000','21-04-2000','24-04-2000','01-05-2000','29-05-2000','28-08-2000','25-12-2000','26-12-2000','01-01-2001','13-04-2001','16-04-2001','07-05-2001','28-05-2001','27-08-2001','25-12-2001','26-12-2001','01-01-2002','29-03-2002','01-04-2002','06-04-2002','03-06-2002','04-06-2002','26-08-2002','25-12-2002','26-12-2002','01-01-2003','18-04-2003','21-04-2003','05-05-2003','26-05-2003','25-08-2003','25-12-2003','26-12-2003','01-01-2004','09-04-2004','12-04-2004','03-05-2004','31-05-2004','30-08-2004','25-12-2004','26-12-2004','27-12-2004','28-12-2004','01-01-2005','03-01-2005','25-03-2005','28-03-2005','02-05-2005','30-05-2005','29-08-2005','27-12-2005','28-12-2005','02-01-2006','14-04-2006','17-04-2006','01-05-2006','29-05-2006','28-08-2006','25-12-2006','26-12-2006','02-01-2007','06-04-2007','09-04-2007','07-05-2007','28-05-2007','27-08-2007','25-12-2007','26-12-2007','01-01-2008','21-03-2008','24-03-2008','05-05-2008','26-05-2008','25-08-2008','25-12-2008','26-12-2008','01-01-2009','10-04-2009','13-04-2009','04-05-2009','25-05-2009','31-08-2009','25-12-2009','28-12-2009','01-01-2010','02-04-2010','05-04-2010','03-05-2010','31-05-2010','30-08-2010','24-12-2010','27-12-2010','28-12-2010','31-12-2010','03-01-2011','22-04-2011','25-04-2011','29-04-2011','02-05-2011','30-05-2011','29-08-2011','26-12-2011','27-12-2011')
then 0
else 1
end working_day
from dual
connect by level <= 36525 + sysdate - to_date('01-01-2000') )
SELECT a.ASM_ID,
a.ASM_START_DATE,
a.ASM_END_DATE,
sum(c.working_day) AS Week_Day
From O_ASSESSMENTS a
join calendar_cte c
on c.calendar_date between a.ASM_START_DATE and a.ASM_END_DATE
WHERE a.ASM_QSA_ID IN ('TYPE1') and
a.ASM_END_DATE >= '01/01/2012' -- and a.ASM_ID = 'A00000'
GROUP BY
a.ASM_ID,
a.ASM_START_DATE,
a.ASM_END_DATE
This will produce a virtual table populated with dates from 01 January 2000 to 10 years after the current date, with all weekends marked as non-working days and all days specified in the second in clause (ie. up to 27 December 2011) also marked as non-working days.
The drawback of this method (or any method where the holiday dates are hardcoded into the query) is that each time new holiday dates are defined, every single query that uses this approach will have to have those dates added.
If you can't use a calendar table in Oracle, you might be better off exporting to Excel. Brute force always works.
Networkdays() "returns the number of whole working days between start_date and end_date. Working days exclude weekends and any dates identified in holidays."
Excluding weekends seems fairly straightforward. Every 7-day period will contain two weekend days. You'll just need to take some care with the leftover days.
Holidays are a different story. You have to either store them or pass them as an argument. If you could store them, you'd store them in a calendar table, and your problem would be over. But you can't do that.
So you're looking at passing them as an argument. Off the top of my head--and I haven't had any tea yet this morning--I'd consider a common table expression or a wrapper for a stored procedure.