How to Compare values between rows in access query - sql

I have a table table1 like below. I want to find all H in Status field that is in between two L. The output for mentioned criteria should be 04/01/15, 05/01/15 and 07/01/15. How can I solve this?
Date Status
01/01/15 A
02/01/15 H
03/01/15 L
04/01/15 H
05/01/15 H
06/01/15 L
07/01/15 H
08/01/15 L

I think you can use a query like this:
SELECT
t.Date, t.Status
FROM
yourTable AS t
JOIN (
SELECT MIN(Date) AS minDate, Max(Date) AS maxDate
FROM yourTable
WHERE Status = 'L') AS l
ON t.Date >= l.minDate
AND t.Date <= l.maxDate
AND t.Status <> 'L';

Related

PostgreSQL CROSS JOIN query issue

I would like to improve the following query:
WITH calendar as (
SELECT d
FROM generate_series(
'2015-01-01'::timestamp, '2020-12-01'::timestamp, interval '1 month'
) d
)
SELECT c.d::date AS ord_date,
n.id,
coalesce(nb_cit,0) as nb_cit
FROM (SELECT distinct t.id from "data".taxonomie t where id = '30092') n CROSS JOIN
calendar c
left join
(select date_trunc('month', i2.date_d) as mon, count(c2.id) as nb_cit
from "data".inventaire i2, "data".citation c2 where i2.id = c2.id_inv and c2.id_taxo = '30092'
group by mon) s
on c.d = s.mon
It works when I set an id (in the from and left join). But the idea is to have the result for all the id.
If I don't set this identifier, I get the same result whatever the identifier is.
I think I have to take out the "count(c2.id)" from the left join but I can't figure how to do it.
Help would be welcome !
Best Regards,
Mathias
I think you just want to aggregate by the id as well in the subquery:
SELECT c.d::date AS ord_date,
n.id,
coalesce(s.nb_cit, 0) as nb_cit
FROM (SELECT DISTINCT t.id FROM "data".taxonomie t) n CROSS JOIN
calendar c LEFT JOIN
(SELECT c2.id_taxo, date_trunc('month', i2.date_d) as mon, count(c2.id) as nb_cit
FROM "data".inventaire i2 JOIN
"data".citation c2
ON i2.id = c2.id_inv
GROUP BY c2.id_taxo, mon
) s
ON c.d = s.mon AND n.id = s.id_taxo;

Get all tables where there is no booking on this time or date

So basically I have a tables table. And a bookings table. A table can be assigned to a booking via the table_no column. The booking also has a reservation_time and reservation_date columns. What I'd like my query to do, is to return all tables that aren't linked to a booking on a certain time or date. It's really bugging me.
Here is what my query looks like as of now
select t.id, t.number
FROM tables t JOIN
bookings b
ON b.table_no = t.number JOIN
reservation_time_data r
ON r.id = b.reservation_time
WHERE t.number != b.table_no AND b.reservation_date != '2020-07-22' AND 45 NOT BETWEEN r.start_time AND r.end_time
You seem to want not exists. Based on your sample query, I think this is:
select t.id, t.number
from tables t
where not exists (select 1
from bookings b join
reservation_time_data r
on r.id = b.reservation_time
where b.table_no = t.number and
b.reservation_date = '2020-07-22' and
45 >= r.start_time and
45 <= r.end_time
);
I think you can get it with left join like this
select t.id, t.number FROM tables t Left JOIN bookings b ON b.table_no = t.number
WHERE b.table_no is null AND (b.reservation_date = '2020-07-22' Or b.[your time column here] BETWEEN b.start_time AND b.end_time )

Counting if name appears under a given date

I have a dataframe with a few columns, I will focus on the ones relevant to my issue.
I would like to return the value 1 for cases where a user's name appears in a row associated with a given date.
So here is an example:
user_name date
a 20/1/2019
a 20/1/2019
c 21/1/2019
c 21/1/2019
a 21/1/2019
b 20/1/2019
Using this as an example, this would be my desired output
user_name date val
a 20/1/2019 1
b 20/1/2019 1
c 20/1/2019 0
a 21/1/2019 1
b 21/1/2019 0
c 21/1/2019 1
I had though about use a case statement of sorts with the pseudo logic if name doesn't appear under a specific date then return 0 else return 1
case when user_name not in date then 0 else 1 end
but this doesn't seem to make sense
I think you want a cross join to generate rows and then logic to set the flag:
select u.user_name, d.date,
(case when exists (select 1 from t where t.user_name = u.user_name and t.date = d.date)
then 1 else 0
end) as flag
from (select distinct user_name from t) u cross join
(select distinct date from t) d ;
You may use a calendar table approach here. In the absence of any formal tables containing all dates and users, we can use subqueries in their place:
SELECT DISTINCT
u.user_name,
d.date,
CASE WHEN t.user_name IS NULL THEN 0 ELSE 1 END AS val
FROM (SELECT DISTINCT user_name FROM yourTable) u
CROSS JOIN (SELECT DISTINCT date FROM yourTable) d
LEFT JOIN yourTable t
ON t.user_name = u.user_name AND
t.date = d.date
ORDER BY
d.date,
u.user_name;
Demo

How to optimize this query for my school project

It's my assignment kindly help me to optimize below two queries.
Optimize assignment 1:
SELECT
n.node_id,
MIN(LEAST(n.date,ec.date)) date
FROM
n, ec
WHERE
(n.node_id = ec.node_id_from OR n.node_id = ec.node_id_to)
AND n.date - ec.date > 0
GROUP BY
n.node_id;
Optimize assignment 2:
SELECT
TO_CHAR(CONVERT_TIMEZONE ('UTC','America/Los_Angeles', tableA."date"), 'YYYY-MM') AS "date_month",
COUNT(DISTINCT CASE WHEN (tableB."date" IS NOT NULL) THEN tableB._id ELSE NULL END) AS "tableB.countB",
COUNT(DISTINCT CASE WHEN (tableC."date" IS NOT NULL) THEN tableC._id ELSE NULL END) AS "tableC.countC"
FROM
tableA AS tableA
LEFT JOIN
tableB AS tableB ON (DATE (CONVERT_TIMEZONE ('UTC', 'America/Los_Angeles',tableB."date"))) = (DATE (CONVERT_TIMEZONE ('UTC', 'America/Los_Angeles',tableA."date")))
LEFT JOIN
tableC AS tableC ON (DATE (CONVERT_TIMEZONE ('UTC', 'America/Los_Angeles',tableC."date"))) = (DATE (CONVERT_TIMEZONE ('UTC', 'America/Los_Angeles',tableA."date")))
WHERE
tableA."date" >= CONVERT_TIMEZONE ('America/Los_Angeles', 'UTC', DATEADD (month, -17, DATE_TRUNC('month', DATE_TRUNC('day', CONVERT_TIMEZONE ('UTC', 'America/Los_Angeles',GETDATE ()))))
GROUP BY
1
ORDER BY
1 DESC
LIMIT 500;
use short alias that makes sql query shorter and cleaner.
Here is the optimized version of second query
SELECT DatePart(month, a.Date-8/24) date_month,
sum(case when b.date is Not null then 1 else 0 end) countb,
sum(case when c.date is Not null then 1 else 0 end) countc,
FROM tableA a
LEFT JOIN tableB b
ON b.Date = a.Date -- Timezone offsets are not necessary,
LEFT JOIN tableC c
ON c.date = a.date -- both in same timezone
WHERE a.date >= DateAdd(hour, 8,
DATEADD (month,-17,DATE_TRUNC('month',
GETDATE () ))
GROUP BY 1
ORDER BY 1 DESC LIMIT 500;
Very simple solution for assignment #1
SELECT n.node_id, MIN(ec.date) as date
FROM n
JOIN ec
ON n.node_id IN (ec.node_id_from, ec.node_id_to) AND ec.date < n.date
GROUP BY n.node_id;
just using min(ec.date) instead of MIN(LEAST(n.date,ec.date)).
Because the JOIN already forces the ec.date to be lower than n.date anyway.
Also note that a where clause like
where (x >= y and x <= z)
can be changed to
where (x between y and z)

SQL Server Delete Rows from Table leaving the record with the Max CreationDate

I want to delete the older records from the table based on creation date,leaving the latest one
attempted SQL,but did not work.
SELECT *
--DELETE L
FROM ItemPriceListMap L
LEFT JOIN (
SELECT ItemPriceListUID3,MAX(CAST(CreationDate as DATE)) MaxDate
FROM ItemPriceListMap
GROUP BY ItemPriceListUID3
)M ON L.ItemPriceListUID3 = M.ItemPriceListUID3 AND CAST(L.CreationDate as DATE) = M.MaxDate
WHERE M.ItemPriceListUID3 IS NULL
The view of the mapping
SELECT I.Description,ipl.UnitListPrice1,iplmp.VatMRP,iplmp.CreationDate FROM ItemPriceListMap iplmp
INNER JOIN ItemPriceList ipl ON iplmp.ItemPriceListUID3 = ipl.UID
INNER JOIN Item i ON ipl.ItemUID = i.UID
ORDER BY I.Description,iplmp.CreationDate
EDIT:
More Sample Data
Using this SQL
SELECT I.Description,iplmp.ItemPriceListUID3,iplmp.CreationDate FROM ItemPriceListMap iplmp
INNER JOIN ItemPriceList ipl ON iplmp.ItemPriceListUID3 = ipl.UID
INNER JOIN Item i ON ipl.ItemUID = i.UID
ORDER BY I.Description,iplmp.CreationDate
so after I execute the delete command the highlighted row should be left in the table(yellow),highlighted in blue is the same Item
TRY THIS: You can use your own query by doing some simple changes as below, you have to join as <> with the max date so it will not delete that record, only delete others which matches ItemPriceListUID3 and <> MaxDate
SELECT *
--DELETE L
FROM ItemPriceListMap L
INNER JOIN (SELECT MAX(CAST(CreationDate as DATE)) MaxDate
FROM ItemPriceListMap
) M ON CAST(L.CreationDate as DATE) <> M.MaxDate
Try this :
DELETE L
FROM ItemPriceListMap L
WHERE CreationDate <> (SELECT MAX(CreationDate) MaxDate
FROM ItemPriceListMap LL
WHERE L.ItemPriceListUID3 = LL.ItemPriceListUID3)
Note : Take backup of your data first.
Use a CTE and a row_number
with CTE as
(
select a1.*, row_number() over(
partition by ItemPriceListUID3 -- remove this if you don't need the grouping
order by CreationDate desc) as R_ORD
from ItemPriceListMap a1
)
delete
from CTE
where R_ORD > 1