Query: Find the earliest date with a null entry which still works with no null entries - sql

I am building a query that displays the next due date for users. The number of dates stays the same, but the due date will change, depending on how many records have a comment from the user.
SELECT tbl_Description.Sample,
tbl_Description.User,
Min(tbl_Data.TestDate) As DueDate
FROM tbl_Description
INNER
JOIN tbl_Data
ON tbl_Description.DescriptionID = tbl_Data.DateID
WHERE tbl_Data.Comment IS NULL
GROUP
BY tbl_Description.Sample,
tbl_Description.User;
However, when every record from tbl_Data has a comment, the query returns empty records. This may happen because the WHERE and IS NULL statement returns nothing if every record exists. Preferably, I would still like the null record to appear with something in the [DueDate] field, such as a blank or “Complete” comment.
tbl_Description
Sample User
1 Betty
tbl_Data (v1)
Date Comments
05/01/2018 Orange
05/08/2018 Orange-Brown
05/15/2018
05/22/2018
Query Output
Sample User DueDate
1 Betty 05/15/2018
tbl_Data (v2)
Date Comments
05/01/2018 Orange
05/08/2018 Orange-Brown
05/15/2018 Brown
05/22/2018 Brown-Black
Query Output (Query returns nothing at the moment)
Sample User DueDate
1 Betty Complete
Any help would be appreciated!

Now knowing that we also can group by DescriptionID, I suggest to query the minimum TestDate for records from tbl_Data without a Comment separately and (outer) join the result to the table tbl_Description. This way, each Description is contained in the result, and when all Dates for a Description have a Comment, the DueDate will appear blank:
SELECT tbl_Description.Sample, tbl_Description.User, Uncommented.DueDate
FROM tbl_Description
LEFT JOIN (
SELECT tbl_Data.DateID, Min(tbl_Data.TestDate) AS DueDate
FROM tbl_Data
WHERE (((tbl_Data.Comment) Is Null))
GROUP BY tbl_Data.DateID
) AS Uncommented ON tbl_Description.DescriptionID = Uncommented.DateID;

Related

Ignore duplicates in results of a select statement based upon secondary column

Sorry if the title is a bit confusing, this is my first time posting.
Essentially, I have a table called roombooking, where a room has a room number(r_no), a bookingref (b_ref) and a checkin and checkout date (checkin and checkout respectively). Due to multiple different b_refs, an r_no appears in the table multiple times, with varying checkin and checkout dates.
What I want is to select all r_nos where checkin != "dateX", and for it to display only rooms where it, and any duplicates, do not contain "dateX" in the checkin column.
To provide an example data:
R_NO B_REF CHECKIN
101 999 2019-09
101 998 2019-08
102 997 2019-07
What I essentially want to see when I run my SQL statement (where dateX = 2019-09) is for it to only select 102, as despite 101 (b_ref 998) having a different checkin date, it's duplicate has 2019-09 in the checkin column and so neither appear as a result.
For those wondering, my current SQL is:
SELECT DISTINCT r_no
from roombooking
where checkin != '2019-09';
However (using the example data) this would return both 101 and 102 as results, which I don't want.
Hopefully, this is clear, and again I apologize if not, it's my first time posting.
Break it down into 2 conditions to apply as your filters -
checkin should not equal the specified date
r_no should not be the same r_no in rows where checkin is equal to the specified date
For example,
SELECT DISTINCT r_no FROM roombooking
WHERE
checkin != '2019-09' AND
r_no NOT IN (SELECT DISTINCT r_no FROM roombooking WHERE checkin = '2019-09')
There are multiple ways to achieve this, depending on your use-case and data size. A few options are
Use a sub-query to select duplicate rooms and eliminate them in your main query, as shown above
Use a CTE to select duplicate rooms and eliminate them in your main query by joining with the CTE
Self join on the same table to eliminate duplicate rooms
As far as I understand your requirements, an easy way to go is
select distinct r_no from roombooking r1
where not exists (
select * from roombooking r2
where r1.r_no = r2.r_no
and r2.checkin = '2019-09'

How to find the distinct records when a value was changed in a table with daily snap shots

I have a table that has a SNAP_EFF_DT (date the record was inserted into the table) field. All records are inserted on a daily basis to record any changes a specific record may have. I want to pull out only the dates and values when a change took place from a previous date.
I am using Teradata SQL Assistant to query this data. This is what I have so far:
SEL DISTINCT MIN(a.SNAP_EFF_DT) as SNAP_EFF_DT, CLIENT_ID, FAVORITE_COLOR
FROM CUSTOMER_TABLE
GROUP BY 2,3;
This does give me the first instance of a change to a specific color. However, if a customer first likes blue on 1/1/2019, then changes to green on 2/1/2019, and then changes back to blue on 3/1/2019 I won't get that last change in the results and will assume their current favorite color is green, when in fact it changed back to blue. I would like a code that returns all 3 changes.
Simply use LAG to compare the current and the previous row's color:
SELECT t.*,
LAG(FAVORITE_COLOR)
OVER (PARTITION BY CLIENT_ID
ORDER BY SNAP_EFF_DT) AS prev_color
FROM CUSTOMER_TABLE AS t
QUALIFY
FAVORITE_COLOR <> prev_color
OR prev_color IS NULL
If your Teradata version doesn't support LAG switch to
MIN(FAVORITE_COLOR)
OVER (PARTITION BY CLIENT_ID
ORDER BY SNAP_EFF_DT
ROWS BETWEEN 1 PRECEDING AND 1 PRECEDING) AS prev_color
One method uses JOIN
select ct.*
from CUSTOMER_TABLE ct left join
CUSTOMER_TABLE ctprev
on ctprev.client_id = ct.client_id AND
ctprev.SNAP_EFF_DT = ct.SNAP_EFF_DT - interval '1' day
where ctprev.client_id is null or
(ctprev.FAVORITE_COLOR <> ct.FAVORITE_COLOR or
. . .
);
Note: This assumes that the values are not null, although the logic can be adjusted to handle null values as well.

Access SQL: Calculating Percent Change between two rows

I am trying to calculate the percentage change between two dates in Access.
The user inputs the start date, an end date and the desired percentage change. If the result matches the criteria it should return the name.
Please note this is the dd/mm/yy format.
This is the table I have:
Name | Payment | DateTime
John | 53.00 | 06/01/18
Mike | 23.16 | 12/07/18
Steve | 31.28 | 21/03/18
John | 58.30 | 22/04/18
For example, if the user inputs a start date of 01/01/18, an end date of 23/04/18, and a desired percentage change of 10 percent then it should return the name John.
Currently, this is the query I have:
SELECT Name
FROM UserPayments
WHERE DateTime >= '01/01/18' AND DateTime <= '23/04/18';
I would like to calculate the total percentage change for two entries. This should be the record date immediately after the first date and the date immediately before the second date.
I'm completely stuck on how to do this in Access (SQL).
I think I need to use a join, but I have not done these before.
There should be a Users table with a primary key of something like UserID, and that UserID should be used in the UserPayments table instead of the Name of the user.
Although it would by nice to use functions like First and Last, MS Access will not allow to use ORDER BY for sorting the details in a group defined by GROUP BY. Therefore, you will have to use subqueries to retrieve the two values for the percentage calculation. If you have a Users table like mentionned above and the DateTime value can be assumed to be unique per User, this could look like this:
SELECT Users.Name,
(SELECT TOP 1 Payment FROM UserPayments
WHERE UserID = Users.UserID AND DateTime Between #01/01/2018# And #04/23/2018#
ORDER BY DateTime DESC)
/
(SELECT TOP 1 Payment FROM UserPayments
WHERE UserID = Users.UserID AND DateTime Between #01/01/2018# And #04/23/2018#
ORDER BY DateTime ASC)
-1 AS PercentChange
FROM Users;
Be aware of rounding errors and format the result as a percentage.

MS Access Query to get multiple counts from the same field

I'm querying imported data that has a date/time field that I can't format as date in the table.
Sample:
Ticket Name Date
INC000101 User1 9/5/2016 10:00:34AM
INC000102 User2 9/5/2016 12:02:00PM
INC000103 User1 9/7/2016 3:34:00PM
INC000104 User2 10/1/2016 9:30:23AM
INC000105 User1 10/5/2016 10:20:00AM
INC000106 USer2 10/6/2016 4:56:00PM
I'm trying to get a count of how many tickets each user has per month. Because the Date field comes from the database as a text field, I can't seem to make that format as date/time so I use "left" to filter by month. This is what I've used to get a return on a single User item for the month of October.
SELECT COUNT(*)
FROM 2016YTD
WHERE [Name]='User1' AND left(Date,3) = '10/';
I would like to add counts for User2 through UserX per month so that I can get a count row or column for each the quantity of tickets for each user each month in one report. Everything I've tried won't save the query due to syntax errors in one form or another. I've tried variations of the following query help post as well without success.
SELECT a.distributor_id,
(SELECT COUNT(*) FROM myTable WHERE level='personal' and distributor_id = a.distributor_id) as PersonalCount,
(SELECT COUNT(*) FROM myTable WHERE level='exec' and distributor_id = a.distributor_id) as ExecCount,
(SELECT COUNT(*) FROM myTable WHERE distributor_id = a.distributor_id) as TotalCount
FROM myTable a ;
I'm sure the answer is staring at me, just not sure what at the moment.
Thanks for reading
John
This is only an answer to your first question about how to deal with dates that are stored in text fields.
To get the count for all users for every month you can do:
SELECT [Name], Format([Date],'mmmm') AS Month, COUNT(*) as Count
FROM 2016YTD
GROUP BY [Name], Format([Date],'mmmm')
A text field containing a date that is always in the same format can be treated as a date with Format() so Format([Date],'mmmm') returns the full month name for each date.
you should just need conditional aggregation. I haven't looked at access in a while but probably just something like this:
SELECT
a.distributor_id
,Format([Date],'mmmm') as Month
,SUM(IIF(level='personal',1,0)) as PersonalCount
,SUM(IIF(level='exec',1,0)) as ExecCount
,COUNT(*) as TotalCount
FROM
myTable a
GROUP BY
a.distributor_id
,Format([Date],'mmmm')

How to get duplicate values in all rows filtering by one column

Here is what my table looks like.
Person Date Entry
Person1 05-20-14 142
Person2 05-20-14 443
Person1 05-21-14 248
Person1 05-21-14 142
I need two things.
First the number of times a Person made an entry for the first time.
I tried doing it with these queries. But the problem is I need this information per day.
That is if I query for 05/21, I need to see output
"Person1 1"
142 wont be included because it already exists.
In my query, I am filtering by date already, so I am not sure how to go out and search in the rest of the dates values. Here is what I have.
SELECT PERSON, Count(distinct Entry)
from [table]
where date >= 05/21/2014
and date < 05/22/2014
group by person
order by person.
This gives me
Person1 2
Both 248 and 142 are considered here. How do I look for 142 was an entry already made in previous dates. I am not very good at nested queries.
Thanks for looking.
Will this solve your problem or give you an idea how inner query should be?
SELECT PERSON, Count(distinct Entry)
from [table]
where date >= 05/21/2014
and date < 05/22/2014
and Entry not in (select distinct entry from [table] where date <> 05/21/2014)
group by person
order by person.
in the above query i have just added an inner query to get the distinct entry from other dates
select distinct entry from [table] where date <> 05/21/2014
and i have added the where condition that the current result should not consider those entries by
and Entry not in (select distinct entry from [table] where date <> 05/21/2014)
hope this helps you.
For the first query, it sounds like you need something like this:
SELECT Person
FROM sample
GROUP BY date, person
HAVING date = '05-21-2014'
See http://sqlfiddle.com/#!3/4653d/1
This might also help:
SELECT Person, date
FROM sample
GROUP BY date, person
ORDER BY date
Hopefully that helps, let me know if I am misunderstanding something..