How to Compare Column in one Table to OneOther Value using SQL - sql

I am trying to perform an analysis where I select from a table only rows that fulfill certain criteria. In this instance, I am interested in date criteria. Specifically, in this query:
SELECT * FROM INPUT_TABLE
WHERE THE_DATE<='2018-01-01' and THE_DATE >='2017-01-01'
I wish to replace the strings '2018-01-01' and '2017-01-01'
with a sort of subquery, where I keep the values of the minimum and maximum dates in another table,called VALUE_TABLES which has the following 2 values:
MAX_DATE MIN_DATE
2018-01-01 2017-01-01
How exactly can I do this?

Use JOIN:
SELECT *
FROM INPUT_TABLE i JOIN
(SELECT MIN(DATE) as MIN_DATE, MAX(DATE) as MAX_DATE
FROM TABLE2
) t2
ON i.THE_DATE >= T2.MIN_DATE AND i.THE_DATE <= t2.MAX_DATE;

Related

How to show a row for the dates not in records of a table as zero

I am trying to show the records as zero for the dates not found.
Below is my basic query:
Select date_col, count(distinct file_col), count(*) from tab1
where date_col between 'date1' and 'date2'
group by date_col;
The output is for one date.
I want all the dates to be shown in result.
The general way to deal with this type of problem is to use something called a calendar table. This calendar table contains all the dates which you want to appear in your report. We can create a crude one by using a subquery:
SELECT
t1.date,
COUNT(DISTINCT t2.file_col) AS d_cnt,
COUNT(t2.file_col) AS cnt
FROM
(
SELECT '2018-06-01' AS date UNION ALL
SELECT '2018-06-02' UNION ALL
...
) t1
LEFT JOIN tab1 t2
ON t1.date = t2.date_col
WHERE
t1.date BETWEEN 'date1' and 'date2'
GROUP BY
t1.date;
Critical here is that we left join the calendar table to your table containing the actual data, but we count a column in your data table. This means that zero would be reported for any day not having matching data.
If you are using postgreSQL, you could generate series with necessary dates period.
SELECT
t1.date,
COUNT(DISTINCT t2.file_col) AS d_cnt,
COUNT(t2.file_col) AS cnt
FROM
(
select to_char( '?'::DATE + (interval '1' month * generate_series(0,11)),'yyyy-mm-dd')as month) x
...
) t1
LEFT JOIN tab1 t2
ON t1.date = to_char(t2.date_col,'yyyy-mm')
WHERE
t1.date BETWEEN 'date1' and 'date2'
GROUP BY
t1.date;
In this example show how to generate sequence for month period.

Calculating business days in Teradata

I need help in business days calculation.
I've two tables
1) One table ACTUAL_TABLE containing order date and contact date with timestamp datatypes.
2) The second table BUSINESS_DATES has each of the calendar dates listed and has a flag to indicate weekend days.
using these two tables, I need to ensure business days and not calendar days (which is the current logic) is calculated between these two fields.
My thought process was to first get a range of dates by comparing ORDER_DATE with TABLE_DATE field and then do a similar comparison of CONTACT_DATE to TABLE_DATE field. This would get me a range from the BUSINESS_DATES table which I can then use to calculate count of days, sum(Holiday_WKND_Flag) fields making the result look like:
Order# | Count(*) As DAYS | SUM(WEEKEND DATES)
100 | 25 | 8
However this only works when I use a specific order number and cant' bring all order numbers in a sub query.
My Query:
SELECT SUM(Holiday_WKND_Flag), COUNT(*) FROM
(
SELECT
* FROM
BUSINESS_DATES
WHERE BUSINESS.Business BETWEEN (SELECT ORDER_DATE FROM ACTUAL_TABLE
WHERE ORDER# = '100'
)
AND
(SELECT CONTACT_DATE FROM ACTUAL_TABLE
WHERE ORDER# = '100'
)
TEMP
Uploading the table structure for your reference.
SELECT ORDER#, SUM(Holiday_WKND_Flag), COUNT(*)
FROM business_dates bd
INNER JOIN actual_table at ON bd.table_date BETWEEN at.order_date AND at.contact_date
GROUP BY ORDER#
Instead of joining on a BETWEEN (which always results in a bad Product Join) followed by a COUNT you better assign a bussines day number to each date (in best case this is calculated only once and added as a column to your calendar table). Then it's two Equi-Joins and no aggregation needed:
WITH cte AS
(
SELECT
Cast(table_date AS DATE) AS table_date,
-- assign a consecutive number to each busines day, i.e. not increased during weekends, etc.
Sum(CASE WHEN Holiday_WKND_Flag = 1 THEN 0 ELSE 1 end)
Over (ORDER BY table_date
ROWS Unbounded Preceding) AS business_day_nbr
FROM business_dates
)
SELECT ORDER#,
Cast(t.contact_date AS DATE) - Cast(t.order_date AS DATE) AS #_of_days
b2.business_day_nbr - b1.business_day_nbr AS #_of_business_days
FROM actual_table AS t
JOIN cte AS b1
ON Cast(t.order_date AS DATE) = b1.table_date
JOIN cte AS b2
ON Cast(t.contact_date AS DATE) = b2.table_date
Btw, why are table_date and order_date timestamp instead of a date?
Porting from Oracle?
You can use this query. Hope it helps
select order#,
order_date,
contact_date,
(select count(1)
from business_dates_table
where table_date between a.order_date and a.contact_date
and holiday_wknd_flag = 0
) business_days
from actual_table a

How to select all dates in SQL query

SELECT oi.created_at, count(oi.id_order_item)
FROM order_item oi
The result is the follwoing:
2016-05-05 1562
2016-05-06 3865
2016-05-09 1
...etc
The problem is that I need information for all days even if there were no id_order_item for this date.
Expected result:
Date Quantity
2016-05-05 1562
2016-05-06 3865
2016-05-07 0
2016-05-08 0
2016-05-09 1
You can't count something that is not in the database. So you need to generate the missing dates in order to be able to "count" them.
SELECT d.dt, count(oi.id_order_item)
FROM (
select dt::date
from generate_series(
(select min(created_at) from order_item),
(select max(created_at) from order_item), interval '1' day) as x (dt)
) d
left join order_item oi on oi.created_at = d.dt
group by d.dt
order by d.dt;
The query gets the minimum and maximum date form the existing order items.
If you want the count for a specific date range you can remove the sub-selects:
SELECT d.dt, count(oi.id_order_item)
FROM (
select dt::date
from generate_series(date '2016-05-01', date '2016-05-31', interval '1' day) as x (dt)
) d
left join order_item oi on oi.created_at = d.dt
group by d.dt
order by d.dt;
SQLFiddle: http://sqlfiddle.com/#!15/49024/5
Friend, Postgresql Count function ignores Null values. It literally does not consider null values in the column you are searching. For this reason you need to include oi.created_at in a Group By clause
PostgreSql searches row by row sequentially. Because an integral part of your query is Count, and count basically stops the query for that row, your dates with null id_order_item are being ignored. If you group by oi.created_at this column will trump the count and return 0 values for you.
SELECT oi.created_at, count(oi.id_order_item)
FROM order_item oi
Group by io.created_at
From TechontheNet (my most trusted source of information):
Because you have listed one column in your SELECT statement that is not encapsulated in the count function, you must use a GROUP BY clause. The department field must, therefore, be listed in the GROUP BY section.
Some info on Count in PostgreSql
http://www.postgresqltutorial.com/postgresql-count-function/
http://www.techonthenet.com/postgresql/functions/count.php
Solution #1 You need Date Table where you stored all date data. Then do a left join depending on period.
Solution #2
WITH DateTable AS
(
SELECT DATEADD(dd, 1, CONVERT(DATETIME, GETDATE())) AS CreateDateTime, 1 AS Cnter
UNION ALL
SELECT DATEADD(dd, -1, CreateDateTime), DateTable.Cnter + 1
FROM DateTable
WHERE DateTable.Cnter + 1 <= 5
)
Generate Temporary table based on your input and then do a left Join.

Efficiently group by column aggregate

SELECT date, id, sum(revenue)
FROM table
WHERE date between '2013-01-01' and '2013-01-08'
GROUP BY date, id
HAVING sum(revenue)>1000
Returns rows that have revenue>1000.
SELECT date, id, sum(revenue)
FROM table
WHERE date between '2013-01-01' and '2013-01-08'
AND id IN (SELECT id FROM table where date between '2013-01-01' and '2013-01-08' GROUP BY id HAVING sum(revenue)>1000)
GROUP BY date, id
Returns rows for id's whose total revenue over the date period is >1000 as desired. But this query is much slower. Any quicker way to do this?
Make sure you have indexes on the date and id columns, and try this variation:
select t.date, t.id, sum(t.revenue)
from table t
inner join (
select id
from table
where date between '2013-01-01' and '2013-01-08'
group by id
having sum(revenue) > 1000
) ts on t.id = ts.id
where t.date between '2013-01-01' and '2013-01-08'
group by t.date, t.id
it's not MySQL, it's Vertica ;)
Cris, what projection and order by you using in CREATE TABLE ???
Do you try using database designer
see http://my.vertica.com/docs/6.1.x/HTML/index.htm#14415.htm

Valid price at given date

got a table with dates and prices.
Date Price
2012-01-01 25
2012-01-05 12
2012-01-10 10
Is there some kind of function that lets me find what the current price where at '2012-01-07'? Without me knowing of the other dates.
Pseudoquery: select price where currentprice('2012-01-07')
Thanks!
MySQL:
select price from your_table
where date <= '2012-01-07'
order by date desc
limit 1
SQL Server:
select top 1 price from your_table
where date <= '2012-01-07'
order by date desc
If you don't have use of ROW_NUMBER(), and want a generic solution, you need to join on a sub-query.
Get the date you want, then get the data for that date.
SELECT
*
FROM
yourTable
INNER JOIN
(
SELECT MAX(yourDate) AS maxDate FROM yourTable WHERE yourDate <= #dateParameter
)
AS lookup
ON yourTable.yourDate = lookup.maxDate
select price
from table1 t
where t.date = ( select max(t2.date)
from table1 t2
where t2.date <= '2012-01-07' )
Note this is not the copy&paste answer, as we're not not knowing what is the datatype for your date column.