tdate issue I'm facing in SQL query - sql

While fetching count from table by using following query
Select count(*)
from tab
where tdate = '17-05-19' ---> output 0
or
Select count(*)
from tab
where trunc(tdate) = '17-05-19' ---->output 0
If I use:
Select count(*)
from tab
where tdate >sysdate - 1 ---> it returns some count(yesterday+some of the today txn)
But here I want only yesterday txn whenever I fire this query.

But here I want only yesterday txn whenever I fire this query.
You may use this.
Select count (*) from tab where
tdate >= TRUNC(SYSDATE) - 1
AND tdate < TRUNC(SYSDATE)
The advantage of this over using TRUNC on the date column is that it will utilize an index if it exists over tdate

If you tried by using
Select count(*) from tab where trunc(tdate) = date'2019-05-17'
(or, you could use
Select count(*) from tab where to_char(tdate,'dd-mm-yy') = '17-05-19' by formatting through to_char function
or, you could use
Select count(*) from tab where trunc(tdate) = trunc(sysdate)-1 to get only the data for the day before
)
you'd get some results provided you have data for the date 17th May.
So, you need to provide a formatting for your literal as date'2019-05-17'(known as date literal) especially for Oracle DB, it might be used as '2019-05-17' without date part in MySQL as an example.
Btw, trunc function is used to extract the date portion, and remove the time part of a date type column value.
If your table is populated with huge data, therefore performance may matter, then you can even create functional index on trunc(tdate).
Demo

Related

SQL Why am I getting the invalid identifier error?

I am trying to use columns that I created in this query to create another column.
Let me first my messy query. The query looks like this:
SELECT tb.team, tb.player, tb.type, tb.date, ToChar(Current Date-1, 'DD-MON-YY') as yesterday,
CASE WHEN to_date(tb.date) = yesterday then 1 else 0 end dateindicator,
FROM (
COUNT DISTINCT(*)
FROM TABLE_A, dual
where dateindicator = 1
Group by tb.team
)
What I am trying to do here is:
creating a column with "Yesterday's date"
Using the "Yesterday" column to create another column called dateindicator indicating each row is yesterday's data or not.
then using that dateindicator, I want to count the distinct number of player for each team that has 1 of the dateindicator column.
But I am getting the "invalid identifier" error. I am new to this oracle SQL, and trying to learn here.
You cannot use an Alias in your Select statement.
see here: SQL: Alias Column Name for Use in CASE Statement
you need to use the full toChar(.. in the CASE WHEN.
Also:
Your WHERE-condition (Line 5) doesnt belong there.. it should be:
SELECT DISTINCT .>. FROM .>. WHERE. you have to specify the table first. then you can filter it with where.
If I follow your explanation correctly: for each team, you want to count the number of players whose date column is yesterday.
If so, you can just filter and aggregate:
select team, count(*) as cnt
from mytable
where mydate >= trunc(sysdate) - 1 and mydate < trunc(sysdate)
group by team
This assumes that the dates are stored in column mydate, that is of date datatype.
I am unsure what you mean by counting distinct players; presumably, a given player appears just once per team, so I used count(*). If you really need to, you can change that to count(distinct player).
Finally: if you want to allow teams where no player matches, you can move the filtering logic within the aggregate function:
select team,
sum(case when mydate >= trunc(sysdate) - 1 and mydate < trunc(sysdate) then 1 else 0 end) as cnt
from mytable
group by team

Big query - Schedule Query on an external partitioned table with the keyword #run_date

Because it is client data I've replace in this post the project name and the dataset name by ******)
I'm trying to create a new schedule query in BigQuery on Google cloud platform
The problem is I've got this error in the web Query editor
Cannot query over table '******.raw_bounce_rate' without a filter over column(s) 'dt' that can be used for partition elimination
The thing is I do filter on the column dt.
Here is the scheme of my external partitioned table
Tracking_Code STRING
Pages STRING NULLABLE
Clicks_to_Page INTEGER
Path_Lengths INTEGER
Visit_Number INTEGER
Visitor_ID STRING
Mobile_Device_Type STRING
All_Visits INTEGER
dt DATE
dt is the field of the partition and I selected the option "Require partition filter"
Here is the simplify sql of my query
WITH yesterday_raw_bounce_rate AS (
SELECT *
FROM `******.raw_bounce_rate`
WHERE dt = DATE_SUB(#run_date, INTERVAL 1 DAY)
),
entries_table as (
SELECT dt,
ifnull(Tracking_Code, "sans campagne") as tracking_code,
ifnull(Pages, "page non trackée") as pages,
Visitor_ID,
Path_Lengths,
Clicks_to_Page,
SUM(all_visits) AS somme_visites
FROM
yesterday_raw_bounce_rate
GROUP BY
dt,
Tracking_Code,
Pages,
Visitor_ID,
Path_Lengths,
Clicks_to_Page
HAVING
somme_visites = 1 and Clicks_to_Page = 1
)
select * from entries_table
if I remove the statement
Clicks_to_Page = 1
or if I replace the
DATE_SUB(#run_date, INTERVAL 1 DAY)
by a hard coded date
the query is accepted by Big Query, it does not make sense to me
Currently, there is an open issue, here. It addresses the error regarding using #run_date filter in the filter of scheduled queries to partitioned tables with required filter. The engineering team is currently working on it, although there is no ETA.
In your scheduled query, you can use one of the two workarounds using #run_date.As follows:
First option,
DECLARE runDateVariable DATE DEFAULT #run_date;
#your code...
WHERE date = DATE_SUB(runDateVariable, INTERVAL 1 DAY)
Second option,
DECLARE runDateVariable DATE DEFAULT CAST(#run_date AS DATE);
#your code...
WHERE date = DATE_SUB(runDateVariable, INTERVAL 1 DAY)
In addition, you can also use CURRENT_DATE() instead of #run_date, as shwon below:
DECLARE runDateVariable DATE DEFAULT CURRENT_DATE();
#your code...
WHERE date = DATE_SUB(runDateVariable, INTERVAL 1 DAY)
UPDATE
I have set up another scheduled query to run daily with a table partitioned by DATE from a field called date_formatted and the partition filter is required. Then I have set up a backfill, here, so I could see the result of the scheduled query for previous days. Below is the code I used:
DECLARE runDateVariable DATE DEFAULT #run_date;
SELECT #run_date as run_date, date_formatted, fullvisitorId FROM `project_id.dataset.table_name` WHERE date_formatted > DATE_SUB(runDateVariable, INTERVAL 1 DAY)

Using the result of a query to determine a value in a where clause in SQL?

So basically I've got a query where I want to filter using a date, however that date may change depending on what datas in the system.
If there's no records with a date of >='X', I want to use >='Y' instead
Currently I've got something like the following mess (Pseudocoded down to avoid using actual table names and such)
With a as (SELECT
count(column_id) as num
FROM tableA
WHERE ADate >= getdate() - 8)
,
b as (SELECT
case when num = '0' then getdate() - 15 else getdate() - 8 end as DateToUseInQuery
from A)
SELECT *
FROM tableB
Bunch of joins to other tables
WHERE BDate >= DateToUseInQuery
The general idea being is if there's no records for the week beforehand, use 2 weeks beforehand
I tried using a query within the where clause like:
WHERE BDate >= (SELECT DateToUseInQuery FROM b)
But the query ran for 11 minutes before I stopped it (Up from about 18 seconds before I tried to put this extra bit in)
I've been thinking about trying to set a variable as the date, but I can't do it in a CTE, and when I do it after, it breaks everything else.
So basically:
Is there an easier way to do this than the cack-handed way I'm trying?
If my way is fine, how can I pass that date properly into the WHERE clause?
You could try something like this. I am using a nested select and case statement to determine the number of days.
There may be a prettier way, but this works.
SELECT COUNT(column_id) AS num FROM TableA
WHERE ADate >=
DATEADD(Day,
(SELECT
CASE
WHEN EXISTS(
SELECT 1 FROM TableA
WHERE ADate >= DATEADD(Day,-8,GETDATE()))
THEN -8
ELSE -15
END AS 'dt')
,GETDATE());

Oracle query displays data by month and year

I want to display the amount of data by month and year. This is an example of displaying data by date:
select count(*) from db.trx where trxdate = to_date('2018-04-23','yyyy-mm-dd')
When I try to display the amount of data by month and year, no query results appear. Is there something wrong with the query?
The query:
select count(*) from db.trx where trxdate = to_date('2018-04','yyyy-mm')
You need to apply the function to trxdate. Using your logic:
SELECT Count(*)
FROM olap.trxh2hpdam
WHERE To_char(trxdate, 'YYYY-MM') = '2018-04';
However, I strongly recommend that you use direct date comparisons:
WHERE trxdate >= date '2018-04-01'
AND
trxdate < date '2018-05-01'
This will allow the database to use an index on trxdate.
There are a couple of ways of accomplishing what you're trying to do. Which one works for you will depend on your database design (for example, the indexes you've created). One way might be this:
SELECT COUNT(*) FROM olap.trxh2hpdam
WHERE TRUNC(trxdate, 'MONTH') = DATE'2018-04-01';
This will round the date down to the first of the month (and, of course, remove any time portion). Then you simply compare it to the first of the month for which you want the data. However, unless you have an index on TRUNC(trxdate, 'MONTH'), this may not be the best course of action; if trxdate is indexed, you'll want to use:
SELECT COUNT(*) FROM olap.trxh2hpdam
WHERE trxdate >= DATE'2018-04-01'
AND trxdate < DATE'2018-05-01';
There are a number of functions at your disposal in Oracle (e.g. ADD_MONTHS()) in the event that the date you use in your query is supposed to be dynamic rather than static.
Just FYI, there is no reason not to use ANSI date literals when trying to retrieve data by day as well. I'm not sure your original query is a good example of getting data for a particular day, since the Oracle DATE datatype does at least potentially include a time:
SELECT COUNT(*) FROM olap.trxh2hpdam
WHERE trxdate >= DATE'2018-04-23'
AND trxdate < DATE'2018-04-24';
or:
SELECT COUNT(*) FROM olap.trxh2hpdam
WHERE TRUNC(trxdate) = DATE'2018-04-23';
EDIT
In case the month and year are dynamic, I would build a date from them (e.g., TO_DATE('<year>-<month>-01', 'YYYY-MM-DD')) and then use the following query:
SELECT COUNT(*) FROM olap.trxh2hpdam
WHERE trxdate >= TO_DATE('<year>-<month>-01', 'YYYY-MM-DD')
AND trxdate < ADD_MONTHS( TO_DATE('<year>-<month>-01', 'YYYY-MM-DD'), 1 );
Hope this helps.

sql query to get today new records compared with yesterday

i have this table:
COD (Integer) (PK)
ID (Varchar)
DATE (Date)
I just want to get the new ID's from today, compared with yesterday (the ID's from today that are not present yesterday)
This needs to be done with just one query, maximum efficiency because the table will have 4-5 millions records
As a java developer i am able to do this with 2 queries, but with just one is beyond my knowledge so any help would be so much appreciated
EDIT: date format is dd/mm/yyyy and every day each ID may come 0 or 1 times
Here is a solution that will go over the base data one time only. It selects the id and the date where the date is either yesterday or today (or both). Then it GROUPS BY id - each group will have either one or two rows. Then it filters by the condition that the MIN date in the group is "today". Those are the id's that exist today but did not exist yesterday.
DATE is an Oracle keyword, best not used as a column name. I changed that to DT. I also assume that your "dt" field is a pure date (as pure as it can be in Oracle, meaning: time of day, which is always present, is 00:00:00).
select id
from your_table
where dt in (trunc(sysdate), trunc(sysdate) - 1)
group by id
having min(dt) = trunc(sysdate)
;
Edit: Gordon makes a good point: perhaps you may have more than one such row per ID, in the same day? In that case the time-of-day may also be different from 00:00:00.
If so, the solution can be adapted:
select id
from your_table
where dt >= trunc(sysdate) - 1 and dt < trunc(sysdate) + 1
group by id
having min(dt) >= trunc(sysdate)
;
Either way: (1) the base table is read just once; (2) the column DT is not wrapped within any function, so if there is an index on that column, it can be used to access just the needed rows.
The typical method would use not exists:
select t.*
from t
where t.date >= trunc(sysdate) and t.date < trunc(sysdate + 1) and
not exists (select 1
from t t2
where t2.id = t.id and
t2.date >= trunc(sysdate - 1) and t2.date < trunc(sysdate)
);
This is a general solution. If you know that there is at most one record per day, there are better solutions, such as using lag().
Use MINUS. I suppose your date column has a time part, so you need to truncate it.
select id from mytable where trunc(date) = trunc(sysdate)
minus
select id from mytable where trunc(date) = trunc(sysdate) - 1;
I suggest the following function index. Without it, the query would have to full scan the table, which would probably be quite slow.
create idx on mytable( trunc(sysdate) , id );