Best way in SQL to eliminate result rows with the same $ value but a day apart - sql

I have an Oracle table that looks like the following
Region
Location
$ Amount
Date
Name
1
Location1
500
2021-01-01
UserA
1
Location1
-500
2021-01-02
UserA
2
Location2
700
2021-01-03
UserB
I want to find and remove the rows where the columns all match except the date is 1 day off and the $ amounts are opposite. In this example I would want to remove rows 1 and 2 because they are opposite $ amounts and only one day off.
Appreciate any help

You can use:
DELETE FROM table_name t
WHERE EXISTS (
SELECT 1
FROM table_name x
WHERE x.region = t.region
AND x.location = t.location
AND x.amount = -t.amount
AND x."DATE" IN (t."DATE" - 1, t."DATE" + 1)
AND x.name = t.name
)
Note: DATE is a keyword and you cannot use it for a column name unless you use a quoted identifier.
db<>fiddle here

This does what you describe:
select t.*
from t
where not exists (select 1
from t t2
where t2.region = t.region and
t2.location = t.location and
t2.name = t.name and
t2.amount = - t.amount and
t2.date in (t.date - 1, t.date + 1)
);
However, you might want to think about how you phrased the problem. What happens if you have 100/-100/100? The logic you describe (and the above query) will remove all three rows. That might be what you intend. If it is not, though, you should ask a new question.
Note: The above removes the rows from a result set. It is easy to modify this for a delete.

Related

Calculate number of rows with having clause

I have 3 tables what I'm trying to achieve is to calculate exact number of rows for two kinds of queries.
The first one must count number of accounts which has exactly only one row in accounts_extra for specific service_id.
The second one must count number of accounts which has exactly only one row in accounts_extra and also trial has not ended for specific id
http://sqlfiddle.com/#!15/313db/3
Basically I get in the first query 0 which is correct but in second query I get 1 which is not correct.
I assume that subscription is optional so that's why I get 1 in the second query what should I do to achieve 0 in the second query but still taken into consideration trial_ends_at
Your question is rather hard to follow, but I think this does what you are describing:
SELECT SUM( (cnt = 1)::int ) as count1,
SUM( (cnt = 1 AND cnt2 > 0)::int ) as count2
FROM (SELECT a.id, COUNT(DISTINCT ae.id) AS cnt,
COUNT(ans.id) as cnt2
FROM accounts a JOIN
accounts_extra ae
ON a.id = ae.account_id LEFT JOIN
account_number_subscriptions ans
ON ans.account_id = a.id AND
ans.trial_ends_at > now()
WHERE a.service_id = '101' AND
a.closed = false AND
ae.created_at < '2019-07-01'
GROUP BY a.id
) a;

Flag on condition

Here's my table :
key date
a 2002
a 2014
a 2011
b 2004
b 2016
b 2001
I'd like a SELECT statement that adds a flag for the most recent date, like that :
key date flag
a 2002 0
a 2014 1
a 2011 0
b 2004 0
b 2016 1
b 2001 0
Thanks
You can use an analytical function if you don't want to do a group by or self-join. You can probably consolidate this a little if you want to, but I find splitting it out using with makes it more obvious what is going on.
with max_date_query as (
select key, date, max(date) over (partition by key) max_date
from mytable
)
select key, date, case when date = max_date then 1 else 0 end flag
from max_date_query
There are other variations on the same theme where you can order the window by date desc and use row_number() instead of max() to determine the flag. I would imagine the one I showed is better, but not sure how much it will really make a difference. You might need to use that method if you have cases where you have duplicate max dates and need to really only choose one.
select t1.*, case when t2.a is null
then 0
else 1
end as flag
from your_table t1
left join
(
select key, max(date) as mdate
from your_table
group by key
) t2 on t1.key = t2.key and t1.date = t2.mdate
Not really sure what the "most recent" condition is (last "X" years?) and assuming the "2015" are in fact DATE values (not char), try:
select
t1.key,
t1.date,
CASE WHEN DATEDIFF('year', t1.date, CURRENT_DATE) < 2 THEN 1 ELSE 0 END as flag
from table t1;
if the "date" in fact is an integer:
select
t1.key,
t1.date,
CASE WHEN EXTRACT(YEAR FROM CURRENT_DATE) - t1.date < 2 THEN 1 ELSE 0 END as flag
from table t1;
Hope it helps
Sérgio

How to sort the query result by the number of specific column in ACCESS SQL?

For example:
This is the original result
Alpha Beta
A 1
B 2
B 3
C 4
After Order by the number of Alpha, this is the result I want
Alpha Beta
B 2
B 3
A 1
C 4
I tried to use GroupBy and OrderBy, but ACCESS always ask me to include all columns.
Why is 'B' placed before 'A' ? I don't understand this order..
Any way, doesn't seem like you need a group by, not from your data sample, but for your desired result you can use CASE EXPRESSION :
SELECT t.alpha,t.beta FROM YourTable t
ORDER BY CASE WHEN t.alpha = 'B' THEN 1 ELSE 0 END DESC,
t.aplha,
t.beta
EDIT: Use this query:
SELECT t.alpha,t.beta FROM YourTable t
INNER JOIN(SELECT s.alpha,count(*) as cnt
FROM YourTable s
GROUP BY s.alpha) t2
ON(t.aplha = t2.alpha)
ORDER BY t2.cnt,t.alpha,t.beta
The query counts number of rows for every distinct Alpha and sorts. General Sql, tweak for ACCESS if needed.
SELECT t1.alpha,t1.beta
FROM t t1
JOIN (
SELECT t2.alpha, count(t2.*) AS n FROM t t2 GROUP BY t2.alpha
) t3 ON t3.alpha = t1.alpha
ORDER BY t3.n, t1.alpha, t1.beta

results of a sub table in the top level query

Not sure how to title this so please feel free to retitle.
I have two tables with a one to many relationship.
Table1
|ID|NAME|...|
Table2
|ID|Table1_ID|StartDate|EndDate|
I am trying to write a query that given a date will return the following
|TABLE1.ID|TABLE1.NAME|are any rows of table 2 in date|
I have a one to many between table 1 and table 2. I want to pass in a date to the query. If any of the many relationships in table 2 have a start date < passed in date and an end date > passed in date or end date is null then I want column 3 of result to be true. Otherwide I want it to be false.
Consider the example
|ID|NAME|...|
| 1|APPLE| ...|
| 2|PEAR| ...|
Table2
|ID|Table1_ID|StartDate|EndDate|
|1|1|01-01-2014|null|
|2|1|01-01-2014|01-02-2014|
|3|2|01-01-2014|01-02-2014|
if I pass in 01-01-2014 then I expect two rows with IDs 1 and 2 and both to be true (all rows match)
if I pass in 01-03-2014 then I expect two rows with ID 1 true (match on first row) and ID 2 to be false (because third row is outside of this date)
I am trying to do this in SQL to eventually convert to JPA. If there are any JPA functions that can do this then that would be good to know. Else I'll do a native query
Any pointers would be great!
Thanks
This should give you what you want:
select x.*, 'PASS' as checker
from table1 x
where exists
(select 'x'
from table2 y
where y.table1_id = x.table1_id
and y.startdate <= '01-01-2014'
and (y.enddate >= '01-01-2014' or y.enddate is null))
union all
select x.*, 'FAIL' as checker
from table1 x
where not exists
(select 'x'
from table2 y
where y.table1_id = x.table1_id
and y.startdate <= '01-01-2014'
and (y.enddate >= '01-01-2014' or y.enddate is null))
I don't know if I understand your question.
So, please, be patient... ;)
Try something like this:
select t1.id, t1.name,
case when t2.Table1_ID is null
then 'false'
else 'true' end as boolean_value
from Table1 t1,
(select distinct Table1_ID
from Table2
where yourdate >= StartDate
and (yourdate <= EndDate or EndDate is null) t2
where t1.id = t2.id (+);

PostgreSQL query with conditional empty values depending on preceding rows

I am working on a postgresql query that i am not sure how to produce the output.
Lets say i have a sql query whose output i want is
name date visit_number visit
x 2011-01-01 123 ?? (value i want=1)
y 2011-01-01 123 ?? (value i want=empty)
a 2011-02-02 345 ?? (value i want=1)
b 2011-02-02 345 ?? (empty)
c 2011-02-02 345 ?? (empty)
currently my sql query contains all the values except the last column visit. I want the visit column to work this way...if visit_number contains same value for multiple rows, i want the column visit to show the value 1 for the first row and just null or empty for the remaining rows where the visit_number is the same. How do i do that???
i could write the sample query in any way.it could simply be :
select name,date,visit_number from sometable order by date;
I am using postgres 8.1 version.
Thanks
The first thing you should do is upgrade to a modern day version of PostgreSQL. Version 8.1 has reached end of life in November 2010.
In a more recent version you can conveniently solve this with window functions:
SELECT name, date, visit_number
, CASE WHEN row_number() OVER (PARTITION BY visit_number
ORDER BY date, name) = 1
THEN 1
ELSE NULL
END AS visit
FROM tbl
ORDER BY date, name;
I ordered by name additionally to break ties.
For versions before PostgreSQL 8.4, this query should work (untested):
SELECT name, date, visit_number
, CASE WHEN EXISTS (
SELECT *
FROM tbl t1
WHERE t1.visit_number = tbl.visit_number -- more to make it unique?
AND t1.date <= tbl.date -- or more columns to make order unambiguous
AND t1.name < tbl.name
)
THEN NULL ELSE 1 END AS visit
FROM tbl
ORDER BY date, name;
This is the query:
select *,
case when row_number() over (partition by visit_number) = 1
then 1
else null
end
from t
Here is an example
Edit:
Without window function:
select t4.*, case when t3.name is not null then 1 end as visit from t t4
left join (
select t1.* from t t1
left join t t2 on t1.name > t2.name and t1.date = t2.date and
t1.visit_number = t2.visit_number
where t2.name is null
) as t3
on t3.name = t4.name and t3.date = t4.date and t3.visit_number = t4.visit_number
Here is an example
NOTE: If name is a key then the last comparison t3.date = t4.date and t3.visit_number = t4.visit_number can be removed