如何从 table 中获取所有行,其中 ID 值不存在于 MySQL 中另一个 table 的两个不同列中的任何一个中?
How to get all rows from a table where the ID value doesn't exist in either of two different columns in another table in MySQL?
我有一个 table 命名的任务。
它包含如下列:taskID、taskName、projectName 等
我还有一个 table 叫做 TaskDependencies。它有两列:
firstTask, secondTask
两者都是引用第一列中的 taskID 的外键。
在项目中,一个任务可以依赖多个任务,多个任务可以依赖一个任务。
TaskDependencies table 用于保存有关哪些任务依赖于哪些任务的数据。
连续,secondTask引用的任务依赖于firstTask引用的任务。
有些任务不依赖于任何其他任务,也没有任何其他任务依赖于它们。因此,并非 Tasks table 中的所有任务都在 TaskDependencies table.
中有引用
我想要实现的是,我想要获得所有你可以添加为依赖于另一个任务的任务,任务 ID = x。
所以我需要将所有不在 TaskDependencies table 中的任务与值 x 放在同一行中。
我用这个来实现:
SELECT * FROM Tasks WHERE taskID
NOT IN(SELECT firstTask FROM TaskDependencies WHERE secondTask = :taskID)
AND taskID NOT IN(SELECT secondTask FROM TaskDependencies WHERE firstTask = :taskID)
AND taskID != :taskID AND projectName = :projectName;
如果我没记错的话它会起作用。
但他们提到在 MySQL 中使用 IN() 函数无效。我尝试了一些使用 JOIN 的方法,但没有成功。
我最后尝试的是:
SELECT * FROM (SELECT * FROM Tasks
LEFT JOIN TaskDependencies as t1 on t1.firstTask = Tasks.taskID
WHERE NOT t1.firstTask <=> 27 AND t1.firstTask IS NULL) as tasks1
INNER JOIN
(SELECT * FROM Tasks
LEFT JOIN TaskDependencies as t2 on t2.secondTask = Tasks.taskID
WHERE NOT t2.secondTask <=> 27 AND t2.secondTask IS NULL) as tasks2 on tasks1.taskID = tasks2.taskID WHERE 1;
但这行不通。
我怎样才能更有效地做到这一点?
这是两个 table 的导出:
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
SET AUTOCOMMIT = 0;
START TRANSACTION;
SET time_zone = "+00:00";
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8mb4 */;
--
-- Database: `stud_v20_keser`
--
-- --------------------------------------------------------
--
-- Table structure for table `TaskDependencies`
--
CREATE TABLE `TaskDependencies` (
`firstTask` int(11) DEFAULT NULL,
`secondTask` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_danish_ci;
--
-- Dumping data for table `TaskDependencies`
--
INSERT INTO `TaskDependencies` (`firstTask`, `secondTask`) VALUES
(24, 27),
(26, 28),
(27, 28),
(25, 23),
(26, 23),
(27, 23);
-- --------------------------------------------------------
--
-- Table structure for table `Tasks`
--
CREATE TABLE `Tasks` (
`taskID` int(11) NOT NULL,
`phaseID` int(11) DEFAULT NULL,
`groupID` int(11) DEFAULT NULL,
`parentTask` int(11) DEFAULT NULL,
`taskName` varchar(45) COLLATE utf8_danish_ci NOT NULL,
`status` int(1) NOT NULL DEFAULT 0,
`projectName` varchar(45) COLLATE utf8_danish_ci DEFAULT NULL,
`timeSpent` int(11) DEFAULT 0,
`estimatedTime` int(11) DEFAULT 0,
`hasSubtask` tinyint(1) NOT NULL DEFAULT 0,
`mainResponsible` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_danish_ci;
--
-- Dumping data for table `Tasks`
--
INSERT INTO `Tasks` (`taskID`, `phaseID`, `groupID`, `parentTask`, `taskName`, `status`, `projectName`, `timeSpent`, `estimatedTime`, `hasSubtask`, `mainResponsible`) VALUES
(23, NULL, 9, NULL, 'Tulle oppgave', 0, 'Noe prosjekt', 0, 32, 1, NULL),
(24, NULL, 9, 23, 'Deloppgave 1', 0, 'Noe prosjekt', 0, 15, 0, NULL),
(25, NULL, 9, 23, 'Deloppgave 2', 0, 'Noe prosjekt', 0, 3, 0, NULL),
(26, NULL, 9, 23, 'deloppgave 3', 0, 'Noe prosjekt', 0, 4, 0, NULL),
(27, NULL, 9, 23, 'Deloppgave 4', 0, 'Noe prosjekt', 0, 6, 0, NULL),
(28, NULL, 9, 23, 'Deloppgave 5', 0, 'Noe prosjekt', 0, 4, 0, NULL);
--
-- Indexes for dumped tables
--
--
-- Indexes for table `TaskDependencies`
--
ALTER TABLE `TaskDependencies`
ADD KEY `First Task FK_idx` (`firstTask`),
ADD KEY `TaskDependencies Second Task FK_idx` (`secondTask`);
--
-- Indexes for table `Tasks`
--
ALTER TABLE `Tasks`
ADD PRIMARY KEY (`taskID`),
ADD KEY `Tasks Project name FK_idx` (`projectName`),
ADD KEY `Tasks phaseID FK_idx` (`phaseID`),
ADD KEY `Tasks groupID FK_idx` (`groupID`),
ADD KEY `Tasks parentTask_idx` (`parentTask`),
ADD KEY `Tasks mainResponsible FK_idx` (`mainResponsible`);
--
-- AUTO_INCREMENT for dumped tables
--
--
-- AUTO_INCREMENT for table `Tasks`
--
ALTER TABLE `Tasks`
MODIFY `taskID` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=29;
--
-- Constraints for dumped tables
--
--
-- Constraints for table `TaskDependencies`
--
ALTER TABLE `TaskDependencies`
ADD CONSTRAINT `TaskDependencies First Task FK` FOREIGN KEY (`firstTask`) REFERENCES `Tasks` (`taskID`) ON DELETE CASCADE ON UPDATE CASCADE,
ADD CONSTRAINT `TaskDependencies Second Task FK` FOREIGN KEY (`secondTask`) REFERENCES `Tasks` (`taskID`) ON DELETE CASCADE ON UPDATE CASCADE;
--
-- Constraints for table `Tasks`
--
ALTER TABLE `Tasks`
ADD CONSTRAINT `Tasks Project name FK` FOREIGN KEY (`projectName`) REFERENCES `Projects` (`projectName`) ON DELETE CASCADE ON UPDATE CASCADE,
ADD CONSTRAINT `Tasks groupID FK` FOREIGN KEY (`groupID`) REFERENCES `Groups` (`groupID`) ON DELETE SET NULL ON UPDATE CASCADE,
ADD CONSTRAINT `Tasks mainResponsible FK` FOREIGN KEY (`mainResponsible`) REFERENCES `Users` (`userID`) ON DELETE SET NULL ON UPDATE CASCADE,
ADD CONSTRAINT `Tasks parentTask FK` FOREIGN KEY (`parentTask`) REFERENCES `Tasks` (`taskID`) ON DELETE CASCADE ON UPDATE CASCADE,
ADD CONSTRAINT `Tasks phaseID FK` FOREIGN KEY (`phaseID`) REFERENCES `Phases` (`phaseID`) ON DELETE SET NULL ON UPDATE CASCADE;
COMMIT;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
我个人的经验是 IN('small','list,'of','items') 没有太大的性能影响。如果您有更大的项目列表,您最好使用 EXISTS。
有关详细信息,请参阅此处:
https://dev.mysql.com/doc/refman/8.0/en/exists-and-not-exists-subqueries.html
你可以用 NOT EXISTS
:
SELECT t.*
FROM Tasks t
WHERE t.taskID <> :taskID
AND NOT EXISTS (
SELECT 1 FROM TaskDependencies d
WHERE (d.firstTask, d.secondTask) IN ((t.taskID, :taskID), (:taskID, t.taskID))
)
或者:
SELECT t.*
FROM Tasks t
WHERE t.taskID <> :taskID
AND NOT EXISTS (
SELECT 1 FROM TaskDependencies d
WHERE LEAST(d.firstTask, d.secondTask) = LEAST(t.taskID, :taskID)
AND GREATEST(d.firstTask, d.secondTask) = GREATEST(t.taskID, :taskID)
)
参见demo。
我有一个 table 命名的任务。
它包含如下列:taskID、taskName、projectName 等
我还有一个 table 叫做 TaskDependencies。它有两列: firstTask, secondTask
两者都是引用第一列中的 taskID 的外键。
在项目中,一个任务可以依赖多个任务,多个任务可以依赖一个任务。
TaskDependencies table 用于保存有关哪些任务依赖于哪些任务的数据。
连续,secondTask引用的任务依赖于firstTask引用的任务。
有些任务不依赖于任何其他任务,也没有任何其他任务依赖于它们。因此,并非 Tasks table 中的所有任务都在 TaskDependencies table.
中有引用我想要实现的是,我想要获得所有你可以添加为依赖于另一个任务的任务,任务 ID = x。
所以我需要将所有不在 TaskDependencies table 中的任务与值 x 放在同一行中。
我用这个来实现:
SELECT * FROM Tasks WHERE taskID
NOT IN(SELECT firstTask FROM TaskDependencies WHERE secondTask = :taskID)
AND taskID NOT IN(SELECT secondTask FROM TaskDependencies WHERE firstTask = :taskID)
AND taskID != :taskID AND projectName = :projectName;
如果我没记错的话它会起作用。
但他们提到在 MySQL 中使用 IN() 函数无效。我尝试了一些使用 JOIN 的方法,但没有成功。
我最后尝试的是:
SELECT * FROM (SELECT * FROM Tasks
LEFT JOIN TaskDependencies as t1 on t1.firstTask = Tasks.taskID
WHERE NOT t1.firstTask <=> 27 AND t1.firstTask IS NULL) as tasks1
INNER JOIN
(SELECT * FROM Tasks
LEFT JOIN TaskDependencies as t2 on t2.secondTask = Tasks.taskID
WHERE NOT t2.secondTask <=> 27 AND t2.secondTask IS NULL) as tasks2 on tasks1.taskID = tasks2.taskID WHERE 1;
但这行不通。
我怎样才能更有效地做到这一点?
这是两个 table 的导出:
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
SET AUTOCOMMIT = 0;
START TRANSACTION;
SET time_zone = "+00:00";
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8mb4 */;
--
-- Database: `stud_v20_keser`
--
-- --------------------------------------------------------
--
-- Table structure for table `TaskDependencies`
--
CREATE TABLE `TaskDependencies` (
`firstTask` int(11) DEFAULT NULL,
`secondTask` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_danish_ci;
--
-- Dumping data for table `TaskDependencies`
--
INSERT INTO `TaskDependencies` (`firstTask`, `secondTask`) VALUES
(24, 27),
(26, 28),
(27, 28),
(25, 23),
(26, 23),
(27, 23);
-- --------------------------------------------------------
--
-- Table structure for table `Tasks`
--
CREATE TABLE `Tasks` (
`taskID` int(11) NOT NULL,
`phaseID` int(11) DEFAULT NULL,
`groupID` int(11) DEFAULT NULL,
`parentTask` int(11) DEFAULT NULL,
`taskName` varchar(45) COLLATE utf8_danish_ci NOT NULL,
`status` int(1) NOT NULL DEFAULT 0,
`projectName` varchar(45) COLLATE utf8_danish_ci DEFAULT NULL,
`timeSpent` int(11) DEFAULT 0,
`estimatedTime` int(11) DEFAULT 0,
`hasSubtask` tinyint(1) NOT NULL DEFAULT 0,
`mainResponsible` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_danish_ci;
--
-- Dumping data for table `Tasks`
--
INSERT INTO `Tasks` (`taskID`, `phaseID`, `groupID`, `parentTask`, `taskName`, `status`, `projectName`, `timeSpent`, `estimatedTime`, `hasSubtask`, `mainResponsible`) VALUES
(23, NULL, 9, NULL, 'Tulle oppgave', 0, 'Noe prosjekt', 0, 32, 1, NULL),
(24, NULL, 9, 23, 'Deloppgave 1', 0, 'Noe prosjekt', 0, 15, 0, NULL),
(25, NULL, 9, 23, 'Deloppgave 2', 0, 'Noe prosjekt', 0, 3, 0, NULL),
(26, NULL, 9, 23, 'deloppgave 3', 0, 'Noe prosjekt', 0, 4, 0, NULL),
(27, NULL, 9, 23, 'Deloppgave 4', 0, 'Noe prosjekt', 0, 6, 0, NULL),
(28, NULL, 9, 23, 'Deloppgave 5', 0, 'Noe prosjekt', 0, 4, 0, NULL);
--
-- Indexes for dumped tables
--
--
-- Indexes for table `TaskDependencies`
--
ALTER TABLE `TaskDependencies`
ADD KEY `First Task FK_idx` (`firstTask`),
ADD KEY `TaskDependencies Second Task FK_idx` (`secondTask`);
--
-- Indexes for table `Tasks`
--
ALTER TABLE `Tasks`
ADD PRIMARY KEY (`taskID`),
ADD KEY `Tasks Project name FK_idx` (`projectName`),
ADD KEY `Tasks phaseID FK_idx` (`phaseID`),
ADD KEY `Tasks groupID FK_idx` (`groupID`),
ADD KEY `Tasks parentTask_idx` (`parentTask`),
ADD KEY `Tasks mainResponsible FK_idx` (`mainResponsible`);
--
-- AUTO_INCREMENT for dumped tables
--
--
-- AUTO_INCREMENT for table `Tasks`
--
ALTER TABLE `Tasks`
MODIFY `taskID` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=29;
--
-- Constraints for dumped tables
--
--
-- Constraints for table `TaskDependencies`
--
ALTER TABLE `TaskDependencies`
ADD CONSTRAINT `TaskDependencies First Task FK` FOREIGN KEY (`firstTask`) REFERENCES `Tasks` (`taskID`) ON DELETE CASCADE ON UPDATE CASCADE,
ADD CONSTRAINT `TaskDependencies Second Task FK` FOREIGN KEY (`secondTask`) REFERENCES `Tasks` (`taskID`) ON DELETE CASCADE ON UPDATE CASCADE;
--
-- Constraints for table `Tasks`
--
ALTER TABLE `Tasks`
ADD CONSTRAINT `Tasks Project name FK` FOREIGN KEY (`projectName`) REFERENCES `Projects` (`projectName`) ON DELETE CASCADE ON UPDATE CASCADE,
ADD CONSTRAINT `Tasks groupID FK` FOREIGN KEY (`groupID`) REFERENCES `Groups` (`groupID`) ON DELETE SET NULL ON UPDATE CASCADE,
ADD CONSTRAINT `Tasks mainResponsible FK` FOREIGN KEY (`mainResponsible`) REFERENCES `Users` (`userID`) ON DELETE SET NULL ON UPDATE CASCADE,
ADD CONSTRAINT `Tasks parentTask FK` FOREIGN KEY (`parentTask`) REFERENCES `Tasks` (`taskID`) ON DELETE CASCADE ON UPDATE CASCADE,
ADD CONSTRAINT `Tasks phaseID FK` FOREIGN KEY (`phaseID`) REFERENCES `Phases` (`phaseID`) ON DELETE SET NULL ON UPDATE CASCADE;
COMMIT;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
我个人的经验是 IN('small','list,'of','items') 没有太大的性能影响。如果您有更大的项目列表,您最好使用 EXISTS。
有关详细信息,请参阅此处: https://dev.mysql.com/doc/refman/8.0/en/exists-and-not-exists-subqueries.html
你可以用 NOT EXISTS
:
SELECT t.*
FROM Tasks t
WHERE t.taskID <> :taskID
AND NOT EXISTS (
SELECT 1 FROM TaskDependencies d
WHERE (d.firstTask, d.secondTask) IN ((t.taskID, :taskID), (:taskID, t.taskID))
)
或者:
SELECT t.*
FROM Tasks t
WHERE t.taskID <> :taskID
AND NOT EXISTS (
SELECT 1 FROM TaskDependencies d
WHERE LEAST(d.firstTask, d.secondTask) = LEAST(t.taskID, :taskID)
AND GREATEST(d.firstTask, d.secondTask) = GREATEST(t.taskID, :taskID)
)
参见demo。