Return a NULL value if Date not in CTE - sql

I have a query that counts the number of records imported for every day according to the current date. The only problem is that the count only returns when records have been imported and NULLS are ignored
I have created a CTE with one column in MSSQL that lists dates in a certain range e.g. 2019-01-01 - today.
The query that i've currently got is like this:
SELECT TableName, DateRecordImported, COUNT(*) AS ImportedRecords
FROM Table
WHERE DateRecordImported IN (SELECT * FROM DateRange_CTE)
GROUP BY DateRecordImported
I get the results fine for the dates that exist in the table for example:
TableName DateRecordImported ImportedRecords
______________________________________________
Example 2019-01-01 165
Example 2019-01-02 981
Example 2019-01-04 34
Example 2019-01-07 385
....
but I need a '0' count returned if the date from the CTE is not in the Table. Is there a better alternative to use in order to return a 0 count or does my method need altering slightly

You can do LEFT JOIN :
SELECT C.Date, COUNT(t.DateRecordImported) AS ImportedRecords
FROM DateRange_CTE C LEFT JOIN
table t
ON t.DateRecordImported = C.Date -- This may differ use actual column name instead
GROUP BY C.Date; -- This may differ use actual column name instead

Move the position of the CTE from a subquery to the FROM:
SELECT T.TableName,
DT.PCTEDateColumn} AS DateRecordImported,
COUNT(T.{TableIDColumn}) AS ImportedRecords
FROM DateRange_CTE DT
LEFT JOIN [Table] T ON DT.{TEDateColumn} = T.DateRecordImported
GROUP BY DT.{CTEDateColumn};
You'll need to replace the values in braces ({})

You can try this
SELECT TableName, DateRecordImported,
case when DateRecordImported is null
then '0'
else count(*) end AS ImportedRecords
FROM Table full join DateRange_CTE
on Table.DateRecordImported DateRange_CTE.ImportedDate
group by DateRecordImported,ImportedDate
(ImportedDate is name of column of CTE)

Related

SQL: How to join two rows on the same table, based on the same timestamp?

This is a data output table in postgreSQL.
I am looking for a way to join rows 7 and 8 on the timestamp condition to remove the [null] values.
This is the expected output I am looking for.
So that I will only have one row when the timestamp matches.
--------------------------------------------------------
05:32:33 | Pump2Stop | 49
--------------------------------------------------------
Any idea how can this be done?
assuming you only ever have one record per timestamp with a non-null value in a specific column, try this:
SELECT to_timestamp, MAX(str_v), MAX(long_v)
FROM table
GROUP BY to_timestamp;
You can use a self-join
select stp.to_timestamp,
stp.str_v,
strt.long_v
from the_table stp
join the_table strt
on stp.to_timestamp = strt.to_timestamp
and strt.str_v is null
where stp.str_v = 'Pump2Stop'
If I understand correctly, you want all rows -- with the specified rows combined. Based on your comment, I think this does what you want:
select t1.to_timestamp, t1.str_v
coalesce(t2.long_v, t1.long_v)
from t t1 left join
t t2
on t.to_timestamp = t2.to_timestamp and
t.str_v in ('Pump2Stop', 'Pump2Stop')
where t1.str_v is not null;
You can also use a window function:
select t.to_timestamp, t.str_v,
coalesce(long_v, imputed_long_v) as long_v
from (select t.*,
max(long_v) over (partition by to_timestamp) as imputed_long_v
from t
) t
where str_v is not null;

Grouping records on consecutive dates

If I have following table in Postgres:
order_dtls
Order_id Order_date Customer_name
-------------------------------------
1 11/09/17 Xyz
2 15/09/17 Lmn
3 12/09/17 Xyz
4 18/09/17 Abc
5 15/09/17 Xyz
6 25/09/17 Lmn
7 19/09/17 Abc
I want to retrieve such customer who has placed orders on 2 consecutive days.
In above case Xyz and Abc customers should be returned by query as result.
There are many ways to do this. Use an EXISTS semi-join followed by DISTINCT or GROUP BY, should be among the fastest.
Postgres syntax:
SELECT DISTINCT customer_name
FROM order_dtls o
WHERE EXISTS (
SELEST 1 FROM order_dtls
WHERE customer_name = o.customer_name
AND order_date = o.order_date + 1 -- simple syntax for data type "date" in Postgres!
);
If the table is big, be sure to have an index on (customer_name, order_date) to make it fast - index items in this order.
To clarify, since Oto happened to post almost the same solution a bit faster:
DISTINCT is an SQL construct, a syntax element, not a function. Do not use parentheses like DISTINCT (customer_name). Would be short for DISTINCT ROW(customer_name) - a row constructor unrelated to DISTINCT - and just noise for the simple case with a single expression, because Postgres removes the pointless row wrapper for a single element automatically. But if you wrap more than one expression like that, you get an actual row type - an anonymous record actually, since no row type is given. Most certainly not what you want.
What is a row constructor used for?
Also, don't confuse DISTINCT with DISTINCT ON (expr, ...). See:
Select first row in each GROUP BY group?
Try something like...
SELECT `order_dtls`.*
FROM `order_dtls`
INNER JOIN `order_dtls` AS mirror
ON `order_dtls`.`Order_id` <> `mirror`.`Order_id`
AND `order_dtls`.`Customer_name` = `mirror`.`Customer_name`
AND DATEDIFF(`order_dtls`.`Order_date`, `mirror`.`Order_date`) = 1
The way I would think of it doing it would be to join the table the date part with itselft on the next date and joining it with the Customer_name too.
This way you can ensure that the same customer_name done an order on 2 consecutive days.
For MySQL:
SELECT distinct *
FROM order_dtls t1
INNER JOIN order_dtls t2 on
t1.Order_date = DATE_ADD(t2.Order_date, INTERVAL 1 DAY) and
t1.Customer_name = t2.Customer_name
The result you should also select it with the Distinct keyword to ensure the same customer is not displayed more than 1 time.
For postgresql:
select distinct(Customer_name) from your_table
where exists
(select 1 from your_table t1
where
Customer_name = your_table.Customer_name and Order_date = your_table.Order_date+1 )
Same for MySQL, just instead of your_table.Order_date+1 use: DATE_ADD(your_table.Order_date , INTERVAL 1 DAY)
This should work:
SELECT A.customer_name
FROM order_dtls A
INNER JOIN (SELECT customer_name, order_date FROM order_dtls) as B
ON(A.customer_name = B.customer_name and Datediff(B.Order_date, A.Order_date) =1)
group by A.customer_name

SQL: Checking whether dates are present in both tables

I have two tables
RejectionDate:
'2016-07-01'
'2016-08-01'
'2016-09-01'
PayDate:
PayDateStart PayDateEnd
'2016-08-01' '2016-09-01'
I need to check whether all dates from the first table RejectionDate fall into periods stored in the other table PayDate.
Here is a way you can get a flag per row -- which I am guessing is the real intention of the question. Regardless of the database you are using:
select r.*,
(case when exists (select 1
from paydates pd
where r.rejectiondate between p.PayDateStart and p.PayDateEnd
)
then 1 else 0
end) as InRangeFlag
from rejections r;
Join them?
select rd.*
from RejectionDate rd
inner join PayDate pd
on rd.RejectionDate between pd.PayDateStart and pd.PayDateEnd
You can use a query like the following:
SELECT COUNT(*) AS all_dates, COUNT(t2.PayDateEnd) AS all_between_dates
FROM Rejections AS t1
LEFT JOIN PayDate AS t2 ON t1.RejectionDate BETWEEN t2.PayDateStart AND t2.PayDateEnd
The first COUNT returns the number of all records of the first table, whereas the second COUNT returns the number of all records of the first table that have a date that is between start/end date of the second table.
Demo here

How to Return a Query Result Even When Nothing Comes Up for the Results

I have a table called "orders" with the following data:
Date Order_No Ship_Method
-------------------------------------
12/6/2013 1234567 RTS
12/6/2013 7654321
12/7/2013 3456789 RTS
12/7/2013 9876543
12/7/2013 1123456 RTS
12/7/2013 5523847 RTS
12/8/2013 8876549
12/8/2013 7733654
I need a query that will search for how many rows of data have "RTS" in the Ship_Method field and return the following result for the day I run the query (like below):
Date RTS_Shipments
-------------------------
12/8/2013 0
-Anthony C.
EDIT
The query that works for me concerning the above issue is the following (provded by Carth in the answers section):
select
sub.tdate,
count(orders.dt)
from (select to_date(to_char((sysdate-1),'mmddYYYY'),'mmddYYYY') tdate from dual) sub
left join orders on sub.tdate = orders.dt and orders.ship_method like '%RTS%'
group by sub.tdate
In order to get the result you need here you will be required to create a basis for your select in which the term you're filtering on definitively exists and then use that to join to your target table. In my initial answer I was thinking that you could select a variable value directly from dual but since I can't get the syntax of that to work out correctly here are a couple of other ideas. You could create a new "working" table that has all the dates you want to check and then select against that and left join to your target table, or you could create a subselect to hold your intended value and use that as the basis of your statement like this:
select
sub.tdate,
count(orders.dt)
from (select to_date(to_char((sysdate-1),'mmddYYYY'),'mmddYYYY') tdate from dual) sub
left join orders on sub.tdate = orders.dt and orders.ship_method like '%RTS%'
group by sub.tdate
You can use a left join on the same table to get all results and the results that you need. The one that you need you sum 1 and 0 for the one you don't.
That should do.
SELECT to_char(o1.DT, 'MM/DD/YYYY') As "Date",
SUM(case when o1.Ship_Method is null then 0 else 1 end) As RTS_Shipments
FROM orders o1
left join orders o2
on (o1.dt = o2.dt and o2.Ship_Method like '%RTS%')
WHERE trunc(o1.DT) = trunc(SYSDATE)
GROUP BY to_char(o1.DT, 'MM/DD/YYYY')
See it at fiddle: http://sqlfiddle.com/#!4/fd374/6
I've changed the date field to dt because date is a reserved word.
And also. This query can count every date but it will show just the registries for the day you filter: trunc(o1.DT) = trunc(SYSDATE) if you take out this condition you will see every date with the proper count.

Get smallest date for each element in access query

So I have a table containing different elements and dates.
It basically looks like this:
actieElement beginDatum
1 1/01/2010
1 1/01/2010
1 10/01/2010
2 1/02/2010
2 3/02/2010
What I now need is the smallest date for every actieElement.
I've found a solution using a simple GROUP BY statement, but that way the query loses its scope and you can't change anything anymore.
Without the GROUP BY statement I get multiple dates for every actieElement because certain dates are the same.
I thought of something like this, but it also does not work as it would give the subquery more then 1 record:
SELECT s1.actieElement, s1.begindatum
FROM tblActieElementLink AS s1
WHERE (((s1.actieElement)=(SELECT TOP 1 (s2.actieElement)
FROM tblActieElementLink s2
WHERE s1.actieElement = s2.actieElement
ORDER BY s2.begindatum ASC)));
Try this
SELECT s1.actieElement, s1.begindatum
FROM tblActieElementLink AS s1
WHERE s1.begindatum =(SELECT MIN(s2.begindatum)
FROM tblActieElementLink s2
WHERE s1.actieElement = s2.actieElement
);
SELECT DISTINCT T1.actieElement, T1.beginDatum
FROM tblActieElementLink AS T1
INNER JOIN (
SELECT T2.actieElement,
MIN(T2.beginDatum) AS smallest_beginDatum
FROM tblActieElementLink AS T2
GROUP
BY T2.actieElement
) AS DT1
ON T1.actieElement = DT1.actieElement
AND T1.beginDatum = DT1.smallest_beginDatum;
Add a DISTINCT clause to your SELECT.