I want to create a check constraint for my table, where you can't add new line, if the new booking range(start_date, end_date) have intersect with an already submitted row.
But i can't place query in a check constraint. Do you have an idea how to do this?
The tables:
APARTMAN
id INT
price INT
BOOKINGS
id INT
start_date DATE
end_date DATE
apartman_id INT
[apartman_id] IN (SELECT [id] FROM [dbo].[APARTMAN]
WHERE [id] NOT IN (
SELECT [apartman_id] FROM
[dbo].[BOOKINGS]
WHERE
([start_date] <= "requested end_date" AND
[end_date] >= "requested start_date" )
OR
([start_date] <= "requested start_date" AND
[end_date] >= "requested end_date" )
OR
(([start_date] <= "requested end_date" AND [end_date] >= "requested start_date" )
OR
([end_date] <= "requested start_date" AND [end_date] >= "requested end_date" ))
)
)
Here's an instead of trigger that I think handles all scenarios.
CREATE TRIGGER dbo.PreventOverlappingBookings
ON dbo.BOOKINGS INSTEAD OF INSERT, UPDATE
AS
BEGIN
SET NOCOUNT ON;
IF EXISTS (
SELECT 1 FROM inserted AS i
INNER JOIN dbo.BOOKINGS AS b
ON (b.id <> i.id OR i.id = 0) -- 0 for insert
AND b.apartman_id = i.apartman_id
AND ((b.start_date <= i.end_date AND b.end_date >= i.start_date)
OR (b.start_date <= i.start_date AND b.end_date >= i.end_date)
OR (b.end_date <= i.start_date AND b.end_date >= i.end_date))
) OR EXISTS (
-- also make sure there are no overlaps in a set-based insert/update
SELECT 1 FROM inserted AS i
INNER JOIN inserted AS b
ON (b.id <> i.id OR i.id = 0) -- 0 for insert
AND b.apartman_id = i.apartman_id
AND ((b.start_date <= i.end_date AND b.end_date >= i.start_date)
OR (b.start_date <= i.start_date AND b.end_date >= i.end_date)
OR (b.end_date <= i.start_date AND b.end_date >= i.end_date))
)
BEGIN
RAISERROR('Overlapping date range.', 11, 1);
END
ELSE
BEGIN
UPDATE b SET start_date = i.start_date, end_date = i.end_date
FROM dbo.BOOKINGS AS b
INNER JOIN inserted AS i
ON b.id = i.id;
IF ##ROWCOUNT > 0
BEGIN
INSERT dbo.BOOKINGS(start_date, end_date, apartman_id)
SELECT start_date, end_date, apartman_id FROM inserted AS i;
END
END
END
GO
Some answers will suggest a function in a UDF, but I don't trust them (and neither should you, IMHO).
Related
update
table1 a
inner join table2 b on a.unique_id = b.unique_id
set
a.menu_return = sum(
case when b.value1 = 'mainmenu'
and b.value2 = '0' then 1 else 0 end
)
where
a.time_stamp >= '2021-12-17 00:00:00'
and a.time_stamp < '2021-12-18 00:00:00';
ERROR 1111 (HY000): Invalid use of group function
What cause this issue?
I'm not really understand what you try to achieve by this query, but looks as you need to use join with pre-aggregated query like:
update table1 a
inner join (
select
unique_id,
sum( case when value1 = 'mainmenu' and value2 = '0' then 1 else 0 end ) menu_return
from table2
group by unique_id
) b on a.unique_id = b.unique_id
set
a.menu_return = b.menu_return
where
a.time_stamp >= '2021-12-17 00:00:00' and a.time_stamp < '2021-12-18 00:00:00';
You can play with MySQL online here
decreasing running time (select query executing time)
even query is not working
it is reducing code line
there are 80 tables
select
(ant_return_loss_pass='pass')+(ant_cross_isolation_pass='pass') as pass_count,
(ant_return_loss_pass='fail')+(ant_cross_isolation_pass='fail') as fail_count,
(ant_return_loss_pass='') +(ant_cross_isolation_pass='') as blank_count
from
(
select A.serial_no,
A.pass_fail as ant_return_loss_pass
from ant_return_loss A,
(
select max(register_date) as date
from ant_return_loss
where 1=1
and serial_no >= '184500074'
and serial_no <= '184500076'
group by serial_no
) B
where 1 = 1
and A.register_date = B.date
)AA
,(
select A.serial_no,
A.pass_fail as ant_cross_isolation_pass
from ant_cross_isolation A,
(
select max(register_date) as date
from ant_cross_isolation
where 1=1
and serial_no >= '184500074'
and serial_no <= '184500076'
group by serial_no
) B
where 1 = 1
and A.register_date = B.date
)BB
where 1=1
and AA.serial_no = BB.serial_no
not working or working 600 sec
The query below uses explicit join syntax and case expressions to make you query easier to understand:
SELECT
COUNT( CASE WHEN ant_return_loss_pass = 'pass' AND
ant_cross_isolation_pass = 'pass' THEN 1 END ) AS pass_count
, COUNT( CASE WHEN ant_return_loss_pass = 'fail' AND
ant_cross_isolation_pass = 'fail' THEN 1 END ) AS fail_count
, COUNT( CASE WHEN ant_return_loss_pass = '' AND
ant_cross_isolation_pass = '' THEN 1 END ) AS blank_count
FROM (
SELECT
A.serial_no
, A.pass_fail AS ant_return_loss_pass
FROM ant_return_loss A
INNER JOIN (
SELECT MAX( register_date ) AS date
FROM ant_return_loss
WHERE serial_no >= '184500074'
AND serial_no <= '184500076'
GROUP BY serial_no
) B ON A.register_date = B.date
) AA
INNER JOIN (
SELECT
A.serial_no
, A.pass_fail AS ant_cross_isolation_pass
FROM ant_cross_isolation A
INNER JOIN (
SELECT MAX( register_date ) AS date
FROM ant_cross_isolation
WHERE serial_no >= '184500074'
AND serial_no <= '184500076'
GROUP BY serial_no
) B ON A.register_date = B.date
) BB ON AA.serial_no = BB.serial_no
To examine if this can be improved for performance however requires access to your database. For example do you indexes for ant_return_loss.serial_no or ant_cross_isolation.serial_no these will aid the where clauses of the subqueries.
Have you run any explain plans on the query? see: https://dev.mysql.com/doc/refman/5.7/en/explain.html
Note to avoid long running time you can use explain on separated portions of the overall query, look for indexes that may assist: e.g.
explain
SELECT MAX( register_date ) AS date
FROM ant_return_loss
WHERE serial_no >= '184500074'
AND serial_no <= '184500076'
GROUP BY serial_no
then:
explain
SELECT
A.serial_no
, A.pass_fail AS ant_return_loss_pass
FROM ant_return_loss A
INNER JOIN (
SELECT MAX( register_date ) AS date
FROM ant_return_loss
WHERE serial_no >= '184500074'
AND serial_no <= '184500076'
GROUP BY serial_no
) B ON A.register_date = B.date
until you have examined all portions for way to improve performance.
I am trying to make this query work, here is my logic , I am trying to select record thats there is not at LEAST NOT one of these options:
1). status = Approved AND end_date >now
2). status =Approved AND end_date is NULL
3). status = Pending And end_date is NULL & COUNT(id) =1
4). status =Pending AND end_date >now & COUNT(id) =1
5). status =Pending AND end_date <now & COUNT(id) =1
how to accomplish this , this is what I have so far I am not sure how to check for COUNT(id) = 1 in conditions 3, 4, and 5?
SELECT
*
FROM
outreach
WHERE
NOT EXISTS (
SELECT
*
FROM
outreach_links
WHERE
outreach_links.outreach_id = outreach.id
AND STATUS = "Approved"
AND end_date > now()
)
AND NOT EXISTS (
SELECT
*
FROM
outreach_links
WHERE
outreach_links.outreach_id = outreach.id
AND STATUS = "Approved"
AND end_date IS NULL
)
AND NOT EXISTS (
SELECT
*
FROM
outreach_links
WHERE
outreach_links.outreach_id = outreach.id
AND STATUS = "Pending"
AND end_date > now()
)
AND NOT EXISTS (
SELECT
*
FROM
outreach_links
WHERE
outreach_links.outreach_id = outreach.id
AND STATUS = "Pending"
AND end_date IS NULL
)
AND NOT EXISTS (
SELECT
*
FROM
outreach_links
WHERE
outreach_links.outreach_id = outreach.id
AND STATUS = "Pending"
AND end_date < now()
)
select
o.*,
SUM(if(ol.status = "Approved" and (ol.end_date > now() or end_date is null), 1, 0)) as cond1,
SUM(if(ol.status = "Pending" and (ol.end_date != now() or end_date is null), 1, 0)) as cond2
from
outreach o
left join
outreach_links ol on ol.outreach_id = o.id
group by
o.id
having
cond1 = 0 and cond2 != 1
;
Not sure if that's you are looking for, but you can try it.
cond2 != 1 makes your COUNT(id) = 1 condition (if there are more than one linked id in outreach_links cond2 will be greater than 1)
When trying to check date ranges it does not return values. Here st_date and end_date for usr_id = 1 is sequence so it should return only usr_id = 1 values and should not return usr_id = 3 since it is not sequence . If the date range is not in sequence, it should not return any value.
CREATE TABLE #temp(st_date DATE,end_date DATE,usr_id INT)
INSERT #temp
VALUES ('2007-03-01 ','2015-01-31 ',1),
('2015-02-01 ','2017-04-01 ',1),
('2007-03-01 ','2014-01-31 ',2),
('2007-03-01 ','2015-01-31 ',3),
('2015-03-02 ','2017-04-01 ',3)
DECLARE #st_dt DATE = '2009-02-01 00:00:00',#end_dt DATE = '2017-01-01 00:00:00'
SELECT * FROM #temp WHERE #st_dt BETWEEN st_date AND end_date
AND #end_dt BETWEEN st_date AND end_date
DROP TABLE #temp
SELECT *
FROM #temp t
INNER JOIN #temp t2 ON t.usr_id = t2.usr_id AND t.end_date = DATEADD(dd, -1, t2.st_date)
WHERE #st_dt BETWEEN t.st_date AND t.end_date
AND #end_dt BETWEEN t2.st_date AND t2.end_date
I'm using MySQL 5.5.16
I have the following query, which works just fine all by itself.
SELECT DISTINCT i.id,
CASE WHEN e.date > '2012-10-16'
THEN e.date
ELSE '9999-99-99'
END AS date,
CASE WHEN e.date > '2012-10-16'
THEN time
ELSE '99-99-99'
END AS time
FROM items AS i
LEFT JOIN expiration AS e ON ( e.item_id = i.id )
WHERE (
(
data >= '2012-10-16'
AND e.valid=1
)
OR i.never_expires=1
)
AND i.valid=1
ORDER BY date ASC , time ASC
LIMIT 0 , 10
However, when I include it in a a larger query, I get an error Column 'date' in where clause is ambiguous. Here is an example where the query above is inside a JOIN:
SELECT i.id, i.title, i.never_expires,
CASE WHEN e.date> '2012-10-16'
THEN e.date
ELSE '9999-99-99'
END AS date,
CASE WHEN e.date > '2012-10-16'
THEN e.time
ELSE '99-99-99'
END AS time, i.item_price AS price
FROM items AS i
LEFT JOIN expiration AS e ON ( e.item_id = i.id )
JOIN (
SELECT DISTINCT i.id,
CASE WHEN e.date > '2012-10-16'
THEN e.date
ELSE '9999-99-99'
END AS date,
CASE WHEN e.date > '2012-10-16'
THEN time
ELSE '99-99-99'
END AS time
FROM items AS i
LEFT JOIN expiration AS e ON ( e.item_id = i.id )
WHERE (
(
data>= '2012-10-16'
AND e.valid=1
)
OR i.never_expires=1
)
AND i.valid=1
ORDER BY date ASC , time ASC
LIMIT 0 , 10
) AS ilist ON (i.id=ilist.id)
WHERE (
(
date >= '2012-10-16'
AND e.valid=1
)
OR i.never_expires=1
)
AND i.valid=1
ORDER BY dateASC , time ASC
Why is it claiming that date is ambiguous?
PS
I've tried replacing date in the AS date part of the inner query with a inner_date, but that just throws another error Unknown column 'inner_date' in 'where clause'...
You are joining the expiration table, which has a column named date, to the materialised table which itself has a column (from the CASE expression) named date. You should qualify the use of date in your WHERE clause with the alias of whichever table you were intending to reference.
Either:
WHERE (
(
ilist.date >= '2012-10-16'
AND e.valid=1
)
Or:
WHERE (
(
e.date >= '2012-10-16'
AND e.valid=1
)