sql-server - دالة - عدم تكرار السجل في الاستعلام
كيف يمكنني إزالة الصفوف المكررة؟ (20)
ما هي أفضل طريقة لإزالة الصفوف المكررة من جدول SQL Server
كبير إلى حد كبير (أي 300،000+ صفوف)؟
الصفوف ، بطبيعة الحال ، لن تكون مكررة مثالية بسبب وجود حقل هوية RowID
.
طاولتي
RowID int not null identity(1,1) primary key,
Col1 varchar(20) not null,
Col2 varchar(2048) not null,
Col3 tinyint not null
من مستوى التطبيق (للأسف). أوافق على أن الطريقة الصحيحة لمنع الازدواجية هي على مستوى قاعدة البيانات من خلال استخدام فهرس فريد ، ولكن في SQL Server 2005 ، لا يُسمح بوجود فهرس سوى 900 بايت ، ويطلق الحقل varchar (2048) الخاص بي هذه المسافة.
أنا لا أعرف كيف سيؤدي ، ولكن أعتقد أنك يمكن أن تكتب الزناد لفرض هذا ، حتى لو كنت لا يمكن أن تفعل ذلك مباشرة مع مؤشر. شيء مثل:
-- given a table stories(story_id int not null primary key, story varchar(max) not null)
CREATE TRIGGER prevent_plagiarism
ON stories
after INSERT, UPDATE
AS
DECLARE @cnt AS INT
SELECT @cnt = Count(*)
FROM stories
INNER JOIN inserted
ON ( stories.story = inserted.story
AND stories.story_id != inserted.story_id )
IF @cnt > 0
BEGIN
RAISERROR('plagiarism detected',16,1)
ROLLBACK TRANSACTION
END
أيضا ، varchar (2048) أصوات مريب لي (بعض الأشياء في الحياة هي 2048 بايت ، لكنها غير شائعة) ؛ يجب أن لا يكون حقا varchar (كحد أقصى)؟
إنشاء جدول فارغ جديد بنفس البنية
تنفيذ استعلام مثل هذا
INSERT INTO tc_category1 SELECT * FROM tc_category GROUP BY category_id, application_id HAVING count(*) > 1
ثم تنفيذ هذا الاستعلام
INSERT INTO tc_category1 SELECT * FROM tc_category GROUP BY category_id, application_id HAVING count(*) = 1
أفضّل استخدام subQery \ having count (*)> 1 للحل الداخلي لأنني أجد أنه أسهل في القراءة وكان من السهل جدًا التحويل إلى عبارة SELECT للتحقق من ما سيتم حذفه قبل تشغيله.
--DELETE FROM table1
--WHERE id IN (
SELECT MIN(id) FROM table1
GROUP BY col1, col2, col3
-- could add a WHERE clause here to further filter
HAVING count(*) > 1
--)
إليك مقالة جيدة أخرى حول إزالة العناصر المكررة .
ويناقش سبب قوته: " يستند SQL على الجبر العلائقي ، ولا يمكن أن يحدث التكرار في الجبر العلائقي ، لأن التكرارات غير مسموح بها في مجموعة. "
حل الجدول المؤقت ، واثنين من الأمثلة على mysql.
في المستقبل ستقوم بمنعه على مستوى قاعدة البيانات ، أو من منظور تطبيق. أود أن أقترح مستوى قاعدة البيانات لأن قاعدة البيانات الخاصة بك ينبغي أن تكون مسؤولة عن الحفاظ على التكامل المرجعي ، والمطورين فقط سوف يسبب مشاكل ؛)
الاستعلام التالي مفيد لحذف الصفوف المكررة. يحتوي الجدول في هذا المثال على ID
كـ عمود هوية والأعمدة التي تحتوي على بيانات مكررة هي Column1
و Column2
و Column3
.
DELETE FROM TableName
WHERE ID NOT IN (SELECT MAX(ID)
FROM TableName
GROUP BY Column1,
Column2,
Column3
/*Even if ID is not null-able SQL Server treats MAX(ID) as potentially
nullable. Because of semantics of NOT IN (NULL) including the clause
below can simplify the plan*/
HAVING MAX(ID) IS NOT NULL)
يعرض البرنامج النصي التالي استخدام GROUP BY
و HAVING
و ORDER BY
في استعلام واحد ، ويعرض النتائج مع عمود مكرر وعددها.
SELECT YourColumnName,
COUNT(*) TotalCount
FROM YourTableName
GROUP BY YourColumnName
HAVING COUNT(*) > 1
ORDER BY COUNT(*) DESC
الطريقة الأخرى هي إنشاء جدول جديد بنفس الحقول ومع فهرس فريد . ثم نقل جميع البيانات من الجدول القديم إلى الجدول الجديد . تلقائيا تجاهل خادم SQL (هناك أيضا خيار حول ما يجب فعله إذا كان سيكون هناك قيمة مكررة: تجاهل أو مقاطعة أو sth) قيم مكررة. لذلك لدينا نفس الجدول بدون صفوف مكررة. إذا كنت لا تريد "فهرس فريد" ، فستتمكن من إسقاطه بعد نقل البيانات .
خاصة بالنسبة للجداول الأكبر ، يمكنك استخدام حزمة DTS (SSIS لاستيراد / تصدير البيانات) لنقل جميع البيانات بسرعة إلى جدولك المفهرس الجديد بشكل فريد. ل 7 ملايين صف يستغرق بضعة دقائق فقط.
بافتراض عدم وجود فراغات ، تقوم GROUP BY
بأعمدة فريدة ، ثم SELECT
MIN (or MAX)
RowId كصف يحتفظ به. بعد ذلك ، احذف فقط كل ما لم يكن لديه رقم صف:
DELETE FROM MyTable
LEFT OUTER JOIN (
SELECT MIN(RowId) as RowId, Col1, Col2, Col3
FROM MyTable
GROUP BY Col1, Col2, Col3
) as KeepRows ON
MyTable.RowId = KeepRows.RowId
WHERE
KeepRows.RowId IS NULL
في حال كان لديك GUID بدلاً من عدد صحيح ، يمكنك استبداله
MIN(RowId)
مع
CONVERT(uniqueidentifier, MIN(CONVERT(char(36), MyGuidColumn)))
بالطبع. استخدم جدول مؤقت. إذا كنت تريد بيانًا واحدًا ، لا يمثل أداءً جيدًا "يعمل" ، يمكنك استخدام:
DELETE FROM MyTable WHERE NOT RowID IN
(SELECT
(SELECT TOP 1 RowID FROM MyTable mt2
WHERE mt2.Col1 = mt.Col1
AND mt2.Col2 = mt.Col2
AND mt2.Col3 = mt.Col3)
FROM MyTable mt)
بشكل أساسي ، لكل صف في الجدول ، يقوم التحديد الفرعي بالبحث عن RowID العلوي لجميع الصفوف التي تشبه بالضبط الصف قيد النظر. حتى ينتهي بك الأمر مع قائمة من الصفوف التي تمثل الصفوف غير الأصلية "غير الأصلية".
سيؤدي هذا إلى حذف الصفوف المكررة ، باستثناء الصف الأول
DELETE
FROM
Mytable
WHERE
RowID NOT IN (
SELECT
MIN(RowID)
FROM
Mytable
GROUP BY
Col1,
Col2,
Col3
)
راجع ( http://www.codeproject.com/Articles/157977/Remove-Duplicate-Rows-from-a-Table-in-SQL-Server )
طريقة أخرى للقيام بذلك: -
DELETE A
FROM TABLE A,
TABLE B
WHERE A.COL1 = B.COL1
AND A.COL2 = B.COL2
AND A.UNIQUEFIELD > B.UNIQUEFIELD
ظننت أنني سأشارك الحل الخاص بي لأنه يعمل في ظل ظروف خاصة. أنا حالتي الجدول مع القيم المكررة لم يكن لديك مفتاح خارجي (لأن القيم كانت مكررة من ديسيبل آخر).
begin transaction
-- create temp table with identical structure as source table
Select * Into #temp From tableName Where 1 = 2
-- insert distinct values into temp
insert into #temp
select distinct *
from tableName
-- delete from source
delete from tableName
-- insert into source from temp
insert into tableName
select *
from #temp
rollback transaction
-- if this works, change rollback to commit and execute again to keep you changes!!
ملاحظة: عند العمل على أشياء مثل هذه أنا دائما استخدام المعاملة ، وهذا لا يضمن فقط يتم تنفيذ كل شيء ككل ، ولكن أيضا يسمح لي لاختبار دون المخاطرة بأي شيء. ولكن بالطبع يجب أن تأخذ نسخة احتياطية على أي حال لمجرد التأكد ...
كان لدي جدول حيث احتجت للحفاظ على صفوف غير مكررة. لست متأكدًا من السرعة أو الكفاءة.
DELETE FROM myTable WHERE RowID IN (
SELECT MIN(RowID) AS IDNo FROM myTable
GROUP BY Col1, Col2, Col3
HAVING COUNT(*) = 2 )
من خلال استخدام الاستعلام أدناه ، يمكننا حذف السجلات المتكررة استنادًا إلى العمود المفرد أو العمود المتعدد. أدناه الاستعلام هو حذف استناداً إلى عمودين. اسم الجدول هو: testing
وأسماء العمود empno,empname
DELETE FROM testing WHERE empno not IN (SELECT empno FROM (SELECT empno, ROW_NUMBER() OVER (PARTITION BY empno ORDER BY empno)
AS [ItemNumber] FROM testing) a WHERE ItemNumber > 1)
or empname not in
(select empname from (select empname,row_number() over(PARTITION BY empno ORDER BY empno)
AS [ItemNumber] FROM testing) a WHERE ItemNumber > 1)
هذه هي أسهل طريقة لحذف السجل المكرر
DELETE FROM tblemp WHERE id IN
(
SELECT MIN(id) FROM tblemp
GROUP BY title HAVING COUNT(id)>1
)
http://askme.indianyouth.info/details/how-to-dumplicate-record-from-table-in-using-sql-105
وأود أن أذكر هذا النهج ، فضلا عن أنه يمكن أن يكون مفيدا ، ويعمل في جميع خوادم SQL: في كثير من الأحيان هناك واحد فقط - اثنين من التكرارات ، والمعروف وعدد من التكرارات معروفة. في هذه الحالة:
SET ROWCOUNT 1 -- or set to number of rows to be deleted
delete from myTable where RowId = DuplicatedID
SET ROWCOUNT 0
يمكن العثور على حل سهل آخر على الرابط الذي تم لصقه http://www.codeproject.com/Articles/157977/Remove-Duplicate-Rows-from-a-Table-in-SQL-Server . هذا واحد سهل الفهم ويبدو أن تكون فعالة لمعظم المشاكل المماثلة. إنه من أجل SQL Server بالرغم من أن المفهوم المستخدم أكثر من مقبول.
فيما يلي الأجزاء ذات الصلة من الصفحة المرتبطة:
خذ بعين الاعتبار هذه البيانات:
EMPLOYEE_ID ATTENDANCE_DATE
A001 2011-01-01
A001 2011-01-01
A002 2011-01-01
A002 2011-01-01
A002 2011-01-01
A003 2011-01-01
إذن كيف يمكننا حذف تلك البيانات المكررة؟
أولاً ، أدخل عمود هوية في هذا الجدول باستخدام التعليمة البرمجية التالية:
ALTER TABLE dbo.ATTENDANCE ADD AUTOID INT IDENTITY(1,1)
استخدم التعليمة البرمجية التالية لحلها:
DELETE FROM dbo.ATTENDANCE WHERE AUTOID NOT IN (SELECT MIN(AUTOID) _
FROM dbo.ATTENDANCE GROUP BY EMPLOYEE_ID,ATTENDANCE_DATE)
CREATE TABLE car(Id int identity(1,1), PersonId int, CarId int)
INSERT INTO car(PersonId,CarId)
VALUES(1,2),(1,3),(1,2),(2,4)
--SELECT * FROM car
;WITH CTE as(
SELECT ROW_NUMBER() over (PARTITION BY personid,carid order by personid,carid) as rn,Id,PersonID,CarId from car)
DELETE FROM car where Id in(SELECT Id FROM CTE WHERE rn>1)
DELETE
FROM
table_name T1
WHERE
rowid > (
SELECT
min(rowid)
FROM
table_name T2
WHERE
T1.column_name = T2.column_name
);
DELETE LU
FROM (SELECT *,
Row_number()
OVER (
partition BY col1, col1, col3
ORDER BY rowid DESC) [Row]
FROM mytable) LU
WHERE [row] > 1
SELECT DISTINCT *
INTO tempdb.dbo.tmpTable
FROM myTable
TRUNCATE TABLE myTable
INSERT INTO myTable SELECT * FROM tempdb.dbo.tmpTable
DROP TABLE tempdb.dbo.tmpTable