背景信息:我们有一个社区会议室,可以通过窗帘分成两半。在过去,当一个团队需要整个房间时,我们放入两个条目,每半个一个...但是我们已经修改了软件(MRBS),因此现在有3个房间(Full {1},Closet Side {2}和Kitchen Side {3})和软件检查当已经预订满员时您不能预留部分房间,反之亦然。但是我们有很多旧的"完整的房间"保留双方的预订。所以2& 3是相同的我需要将其中一个预订移至1并删除另一个。
所以我有一张表如:
id room_id start_time name
1 2 13:00 Meeting
2 2 15:00 Meeting
3 3 15:00 Meeting
4 3 13:00 Storytime
我想要通过桌子,当房间2& 3两者同时具有条目并且具有相同的名称我想将房间2的room_id更改为1并删除房间3的条目。因此在上面的示例中,条目2将被修改并且条目3将被删除
我相当确定这需要两个单独的查询; EG首先匹配将所有room_id更改为2到1,然后作为单独的查询,比较房间1和3并删除3上的条目。
我认为这对于更改房间2到1很接近:
UPDATE `mrbs_entry`
JOIN `mrbs_entry` AS `other_side` ON `other_side.room_id` = '3'
AND `other_side.name` = `mrbs_entry.name`
AND `other_side.start_time` = `mrbs_entry.start_time`
AND `other_side.id` != `mrbs_entry.id`
SET `mrbs_entry.room_id` = '1'
WHERE (`mrbs_entry.room_id` = '2' AND `mrbs_entery.id` IN(92437,92438,92442,92443,92470,92471,92477,92478,92489,89462,92496,90873))
然而我收到#1054 - Unknown column 'mrbs_entry.room_id' in 'field list'
错误
注意:IN(*)位将其限制为几个测试条目,以确保它实际上按预期工作。
答案 0 :(得分:1)
您无法在SET行中使用表名进行更新。 您可能可以将该行更改为
SET `room_id` = '1'
但是从确保查询的工作方式可能更加安全:
UPDATE
`mrbs_entry`
set `room_id` = '1'
WHERE `id` IN
(
SELECT `mrbs_entry.id` FROM
`mrbs_entry`
JOIN `mrbs_entry` AS `other_side` ON `other_side.room_id` = '3'
AND `other_side.name` = `mrbs_entry.name`
AND `other_side.start_time` = `mrbs_entry.start_time`
AND `other_side.id` != `mrbs_entry.id`
WHERE (`mrbs_entry.room_id` = '2' AND `mrbs_entry.id` IN(92437,92438,92442,92443,92470,92471,92477,92478,92489,89462,92496,90873))
) AS T
运行内部查询,直到它拉出正确的id
组,然后运行整个内容来更改room_id
s
答案 1 :(得分:1)
方法1 - 使用临时表的存储过程
如果您准备使用存储过程和临时表,这似乎是最简单的方法:
CREATE PROCEDURE sp_sanitize_mrbs()
BEGIN
DROP TEMPORARY TABLE IF EXISTS mrbs_to_sanitize;
CREATE TEMPORARY TABLE mrbs_to_sanitize (
id int auto_increment primary key,
room2_id int,
room3_id int);
-- "I want to go through the table, and when room 2 & 3 both have
-- entries at the same time and with the same name I want to..."
INSERT INTO mrbs_to_sanitize (room2_id, room3_id)
SELECT m1.id, m2.id
FROM mrbs_entry m1
CROSS JOIN mrbs_entry m2
WHERE m1.start_time = m2.start_time
AND m1.name = m2.name
AND m1.room_id = 2
AND m2.room_id = 3;
-- ...change room 2's room_id to 1
UPDATE mrbs_entry me
JOIN mrbs_to_sanitize mts
ON me.id = mts.room2_id
SET me.room_id = 1;
-- "...and delete the entry for room 3."
DELETE me
FROM mrbs_entry me
JOIN mrbs_to_sanitize mts
ON me.id = mts.room3_id;
END//
-- ...
-- The Stored Procedure can now be called any time you like:
CALL sp_sanitize_mrbs();
请参阅SQL Fiddle Demo - using a Stored Procedure
方法2 - 不带存储过程
以下“技巧”稍微复杂一点,但应该在不使用存储过程,临时表或变量的情况下执行此操作:
-- "I want to go through the table, and when room 2 & 3 both have
-- entries at the same time and with the same name I want to..."
-- "...change room 2's room_id to 1"
UPDATE mrbs_entry m1
CROSS JOIN mrbs_entry m2
-- temporarily mark this row as having been updated
SET m1.room_id = 1, m1.name = CONCAT(m1.name, ' UPDATED')
WHERE m1.start_time = m2.start_time
AND m1.name = m2.name
AND m1.room_id = 2
AND m2.room_id = 3;
-- "...and delete the entry for room 3."
DELETE m2 FROM mrbs_entry m1
CROSS JOIN mrbs_entry m2
WHERE m1.start_time = m2.start_time
AND m1.name = CONCAT(m2.name, ' UPDATED')
AND m1.room_id = 1
AND m2.room_id = 3;
-- now remove the temporary marker to restore previous value
UPDATE mrbs_entry
SET name = LEFT(name, CHAR_LENGTH(name) - CHAR_LENGTH(' UPDATED'))
WHERE name LIKE '% UPDATED';
方法2的解释
第一个查询更新房间号码。但是,正如您所提到的,我们需要在单独的查询中执行删除操作。由于我没有对您的数据进行任何假设,因此一旦修改后获得相同结果的安全方法是引入“标记”以临时指示更新更改了哪一行。 在上面的示例中,此标记为'UPDATED '
,但您可能希望选择更有可能永远不会用于任何其他目的的内容,例如一个随机的字符序列。如果需要,它也可以移动到不同的字段。然后可以执行删除,最后需要删除标记以恢复原始数据。
答案 2 :(得分:0)
我认为你需要实现一个触发器或者更确切地说是一个返回触发器的存储过程。
1)检查条目是否具有相同的标题。 2)更新房间到2到1号房间。 3)删除3号房间的入口。
像这样。
答案 3 :(得分:0)
我会分2步完成。第一步是非破坏性的。通过这种方式,我可以看到第一步看起来是否正确,然后继续对mrbs_entry
进行实际修改。
首先使用自联接创建一个临时表,以发现房间2和3的完全匹配。这个额外的表将有效地列出需要进入房间1的预订,并且它列出了2和3的预订。需要删除。
CREATE TABLE tmp
SELECT a.*
FROM mrbs_entry AS a
JOIN mrbs_entry AS b ON a... = b...
WHERE a.room_id = 2
AND b.room_id = 3;
ON
是start_time
和/或date
和/或name
或其中的一些组合。请注意,只捕获了一组列(a.*
)。
该表故意不是CREATE TEMPORARY TABLE
,而是永久性的表格。表。检查内容以查看是否正确创建。
第二步分为2个查询,但在单个事务中为了一些额外的安全性:
BEGIN;
DELETE mrbs_entry
FROM mrbs_entry
JOIN tmp ON mrbs_entry... = tmp...
WHERE mrbs_entry.room_id IN (2,3); -- delete both reservations
INSERT INTO mrbs_entry
SELECT 1 as room_id, ...
FROM tmp; -- Insert the "full" assignments
COMMIT;
最后清理 - 在你进一步确认改变是好的之后,
DROP TABLE tmp;
答案 4 :(得分:0)
这对我有用,我认为它非常自我解释并遵循您使用两个查询的逻辑。
-- update query
update mrbs_entry
join
(
select t1.*
from mrbs_entry as t1
join mrbs_entry as t2
on
t2.room_id <> t1.room_id -- get different rooms
and t2.start_time = t1.start_time -- with same start time
and t2.name = t1.name -- and same name
where
t1.room_id = 2 -- where the left side has room id 2
and t2.room_id = 3 -- and the right side has room id 3
) as t
on
t.id = mrbs_entry.id -- set those room ids (2) to
set mrbs_entry.room_id = 1 ; -- the new id (1)
-- delete query
delete mrbs_entry
from mrbs_entry
join mrbs_entry as t1
on
t1.room_id <> mrbs_entry.room_id -- same as above, different room ids
and t1.start_time = mrbs_entry.start_time -- same start time
and t1.name = mrbs_entry.name -- same name
where
mrbs_entry.room_id = 3 -- get the stuff that has room id 3 (to get rid of it)
and t1.room_id = 1 -- and new duplicate room id 1
;
答案 5 :(得分:0)
我已经修改了你的陈述并正确worked(至少乍一看)。
powerShell = PowerShell.openSession();
//Print results
System.out.println(powerShell.executeScript("\"C:\\testscript.ps1\"").getCommandOutput());
powerShell.close();
答案 6 :(得分:0)
我对这里的一些答案感到困惑,因为实际问题不是那么难恕我自己。
GROUP BY
&amp; HAVING
)INSERT
)最后,当还有一个(刚插入的)room_id 1条目时,你会删除所有room_id 2和3条目。 (DELETE
)
-- setup
CREATE TABLE mrbs_entry (id int auto_increment primary key, room_id int, start_time varchar(255), name varchar(255));
INSERT INTO mrbs_entry (room_id, start_time, name) VALUES (2, '13:00', 'Meeting');
INSERT INTO mrbs_entry (room_id, start_time, name) VALUES (2, '15:00', 'Meeting');
INSERT INTO mrbs_entry (room_id, start_time, name) VALUES (3, '15:00', 'Meeting');
INSERT INTO mrbs_entry (room_id, start_time, name) VALUES (3, '13:00', 'Storytime');
INSERT INTO mrbs_entry (room_id, start_time, name) VALUES (2, '18:00', 'Test');
INSERT INTO mrbs_entry (room_id, start_time, name) VALUES (3, '18:00', 'Test');
-- step 1: "convert" reservations that book all 'sub-rooms' into a 'full-room' reservation
INSERT `mrbs_entry` (room_id, start_time, name)
SELECT 1, -- full room
start_time,
name
FROM `mrbs_entry` new
WHERE room_id IN (2, 3) -- reserved left and/or right side
-- safety check, avoid inserting the value if it already exists!
AND NOT EXISTS ( SELECT *
FROM `mrbs_entry` old
WHERE old.room_id = 1
AND old.start_time = new.start_time
AND old.name = new.name )
-- must have reserved both sides of the room
GROUP BY start_time,
name
HAVING COUNT(*) = 2;
-- step 2: get rid of all 'sub-room' reservations in case there already is a 'full-room' reservation
DELETE del
FROM `mrbs_entry` del
JOIN `mrbs_entry` fr -- WHERE exists a room_id 1 for same time & name
ON fr.room_id = 1
AND fr.start_time = del.start_time
AND fr.name = del.name
WHERE del.room_id IN (2, 3); -- get rid of half-rooms
PS:我更喜欢在步骤2中使用WHERE EXISTS
语法,但它无法立即开始工作..将会看到我能否在今天晚些时候找到时间(我通常在TSQL中工作,这有点不同)
答案 7 :(得分:0)
按照Steve Chambers解决方案方法2的说法,我会在一次交易的三个步骤中完成。
测试用例:
CREATE TABLE mrbs_entry (id int auto_increment primary key, room_id int, start_time varchar(255), name varchar(255));
INSERT INTO mrbs_entry
(room_id, start_time, name)
VALUES
(2, '13:00', 'Meeting'),
(2, '15:00', 'Meeting'),
(3, '15:00', 'Meeting'),
(3, '13:00', 'Storytime');
解决方案:
START TRANSACTION;
-- 1. Mark one "side" of the pair with temporary artificial room_id = 0.
UPDATE mrbs_entry side2
INNER JOIN mrbs_entry side3 ON side3.room_id = 3 AND
side2.start_time = side3.start_time AND
side2.name = side3.name
SET side2.room_id = 0
WHERE side2.room_id = 2;
-- 2. Delete the other "side" of the pair.
DELETE side3 FROM mrbs_entry side3
INNER JOIN mrbs_entry side0 ON side0.room_id = 0 AND
side0.start_time = side3.start_time AND
side0.name = side3.name
WHERE side3.room_id = 3;
-- 3. Reset the mark to a valid value.
UPDATE mrbs_entry
SET room_id = 1
WHERE room_id = 0;
COMMIT;
如果room_id
存在约束, 这将无法正常工作,但如果没有,这将是最安全和最有效的解决方案。即使存在约束,也可以在事务开始时将room_id = 0
临时添加到可能值列表中,并在提交之前将其删除。