Syp*_*ess 5 sql t-sql sql-server sql-server-ce
这里想要删除具有重复列的值(Product)的行,然后将其用作主键.
该列是类型nvarchar,我们不希望一个产品有2行.数据库很大,我们需要移除大约数千行.
在查询所有重复项期间,我们希望保留第一个项目并删除第二个项目作为重复项目.
还没有主键,我们希望在删除重复项之后进行此操作.然后Productcolumm可能是我们的主要关键.
该数据库是SQL Server CE.
我尝试了几种方法,并且大多数错误类似于:
解析查询时出错.[令牌行号= 2,令牌行偏移= 1,令牌错误= FROM]
我试过的方法:
DELETE FROM TblProducts
FROM TblProducts w
INNER JOIN (
SELECT Product
FROM TblProducts
GROUP BY Product
HAVING COUNT(*) > 1
)Dup ON w.Product = Dup.Product
Run Code Online (Sandbox Code Playgroud)
尝试用类似的东西学习和调整我的代码的首选方法(它还不正确):
SELECT Product, COUNT(*) TotalCount
FROM TblProducts
GROUP BY Product
HAVING COUNT(*) > 1
ORDER BY COUNT(*) DESC
--
;WITH cte -- These 3 lines are the lines I have more doubt on them
AS (SELECT ROW_NUMBER() OVER (PARTITION BY Product
ORDER BY ( SELECT 0)) RN
FROM Word)
DELETE FROM cte
WHERE RN > 1
Run Code Online (Sandbox Code Playgroud)
如果您有两个具有相同“产品”列的不同记录,那么您可以使用某些条件选择不需要的记录,例如
CREATE TABLE victims AS
SELECT MAX(entryDate) AS date, Product, COUNT(*) AS dups FROM ProductsTable WHERE ...
GROUP BY Product HAVING dups > 1;
Run Code Online (Sandbox Code Playgroud)
然后您可以在 ProductTable 和 Victims 之间执行 DELETE JOIN。
或者,您也可以仅选择“产品”,然后对其他一些 JOIN 条件执行 DELETE,例如具有无效的 CustomerId、EntryDate NULL 或其他任何条件。如果您知道产品只有一份有效副本,并且所有其他副本均可通过无效数据识别,则此方法有效。
假设您有相同的记录(或者您有相同和不相同的记录,或者您可能对某些产品有多个重复项,但您不知道是哪一个)。您运行完全相同的查询。然后,您对 ProductsTable 运行 SELECT 查询,并选择 DISTINCT 所有与要进行重复数据删除的产品代码匹配的产品,按产品分组,并为所有字段选择合适的聚合函数(如果相同,则任何聚合都可以。否则我通常尝试 MAX或最小值)。这将为每个产品恰好“保存”一行。
此时,您运行 DELETE JOIN 并删除所有重复的产品。然后,只需将已保存并已删除重复数据的子集重新导入到主表中即可。
当然,在 DELETE JOIN 和 INSERT SELECT 之间,数据库将处于不稳定状态,所有至少有一个重复的产品都会消失。
另一种应该在 MySQL 中工作的方法:
-- Create an empty table
CREATE TABLE deduped AS SELECT * FROM ProductsTable WHERE false;
CREATE UNIQUE INDEX deduped_ndx ON deduped(Product);
-- DROP duplicate rows, Joe the Butcher's way
INSERT IGNORE INTO deduped SELECT * FROM ProductsTable;
ALTER TABLE ProductsTable RENAME TO ProductsBackup;
ALTER TABLE deduped RENAME TO ProductsTable;
-- TODO: Copy all indexes from ProductsTable on deduped.
Run Code Online (Sandbox Code Playgroud)
注意:如果您想区分“良好记录”和“无效重复记录”,上述方法不起作用。仅当您有冗余的重复记录,或者您不关心保留哪一行和丢弃哪一行时,它才有效!
编辑:您说“重复项”具有无效字段。在这种情况下,您可以使用排序技巧修改上面的内容:
SELECT * FROM ProductsTable ORDER BY Product, FieldWhichShouldNotBeNULL IS NULL;
Run Code Online (Sandbox Code Playgroud)
然后,如果您只有一行产品,一切都很好,它将被选中。如果有更多,则将首先选择 (FieldWhichShouldNeverBeNull IS NULL) 为 FALSE 的字段(即 FieldWhichShouldNeverBeNull 实际上不为空的字段),然后插入。由于 IGNORE 子句,所有其他人都会默默地反对产品的独特性。这不是一个非常漂亮的方法(并检查我没有在我的条款中将 true 与 false 混合!),但它应该有效。
编辑
实际上更多的是一个新答案
这是一个简单的表格来说明问题
CREATE TABLE ProductTable ( Product varchar(10), Description varchar(10) );
INSERT INTO ProductTable VALUES ( 'CBPD10', 'C-Beam Prj' );
INSERT INTO ProductTable VALUES ( 'CBPD11', 'C Proj Mk2' );
INSERT INTO ProductTable VALUES ( 'CBPD12', 'C Proj Mk3' );
Run Code Online (Sandbox Code Playgroud)
还没有索引,也没有主键。我们仍然可以声明 Product 为主键。
但不好的事情发生了。两条新记录进入,并且都有 NULL 描述。
然而,第二个是一个有效的产品,因为我们之前对 CBPD14 一无所知,因此我们不想完全失去这个记录。不过,我们确实想摆脱虚假的 CBPD10。
INSERT INTO ProductTable VALUES ( 'CBPD10', NULL );
INSERT INTO ProductTable VALUES ( 'CBPD14', NULL );
Run Code Online (Sandbox Code Playgroud)
粗鲁的 DELETE FROM ProductTable WHERE Description IS NULL 是不可能的,它会杀死不重复的 CBPD14。
所以我们就这样做。首先获取重复项列表:
SELECT Product, COUNT(*) AS Dups FROM ProductTable GROUP BY Product HAVING Dups > 1;
Run Code Online (Sandbox Code Playgroud)
我们假设:“每组坏记录至少有一个好记录”。
我们通过提出相反的假设并进行查询来检查这个假设。如果一切顺利,我们预计此查询不会返回任何内容。
SELECT Dups.Product FROM ProductTable
RIGHT JOIN ( SELECT Product, COUNT(*) AS Dups FROM ProductTable GROUP BY Product HAVING Dups > 1 ) AS Dups
ON (ProductTable.Product = Dups.Product
AND ProductTable.Description IS NOT NULL)
WHERE ProductTable.Description IS NULL;
Run Code Online (Sandbox Code Playgroud)
为了进一步验证,我插入了两条代表这种故障模式的记录;现在我确实希望上面的查询返回新代码。
INSERT INTO ProductTable VALUES ( "AC5", NULL ), ( "AC5", NULL );
Run Code Online (Sandbox Code Playgroud)
现在“check”查询确实返回了,
AC5
Run Code Online (Sandbox Code Playgroud)
所以说,Dups这一代看起来不错。
我现在继续删除所有无效的重复记录。如果存在重复的有效记录,它们将保持重复,除非可以找到某些条件,区分其中一个“好”记录并声明所有其他“无效”(可能使用与描述不同的字段重复该过程)。
但是,有一个问题。目前,您无法在子查询中从表中删除并从同一个表中进行选择(http://dev.mysql.com/doc/refman/5.0/en/delete.html)。因此需要一些解决方法:
CREATE TEMPORARY TABLE Dups AS
SELECT Product, COUNT(*) AS Duplicates
FROM ProductTable GROUP BY Product HAVING Duplicates > 1;
DELETE ProductTable FROM ProductTable JOIN Dups USING (Product)
WHERE Description IS NULL;
Run Code Online (Sandbox Code Playgroud)
现在,这将删除所有无效记录,前提是它们出现在 Dups 表中。
因此,我们的 CBPD14 记录将保持不变,因为它不会出现在那里。CBPD10 的“良好”记录将保持不变,因为其描述不为 NULL。所有其他人——噗。
让我再次声明,如果一条记录没有有效记录,但 它是重复的,那么该记录的所有副本都将被杀死 -不会有幸存者。
为了避免这种情况,可以首先将代表这种故障模式的行选择(使用上面的查询,检查“不应返回任何内容”)到另一个临时表中,然后在删除后将它们插入主表中(使用事务可能是为了)。