कभी-कभी डीबीए के रूप में हमारे रन के दौरान, हम कम से कम एक टेबल पर आते हैं जो डुप्लिकेट रिकॉर्ड से भरी होती है। भले ही तालिका में प्राथमिक कुंजी हो (ज्यादातर मामलों में एक स्वत:वृद्धिशील), शेष फ़ील्ड में डुप्लिकेट मान हो सकते हैं।
हालांकि, SQL सर्वर उन डुप्लिकेट रिकॉर्ड से छुटकारा पाने के कई तरीकों की अनुमति देता है (उदाहरण के लिए सीटीई, एसक्यूएल रैंक फ़ंक्शन, ग्रुप बाय के साथ सबक्वायरी आदि का उपयोग करना)।
मुझे याद है एक बार, एक साक्षात्कार के दौरान, मुझसे पूछा गया था कि प्रत्येक में से केवल 1 को छोड़ते हुए एक तालिका में डुप्लिकेट रिकॉर्ड कैसे हटाएं। उस समय, मैं जवाब नहीं दे पा रहा था, लेकिन मैं बहुत उत्सुक था। थोड़ा शोध करने के बाद, मुझे इस समस्या को हल करने के लिए बहुत सारे विकल्प मिले।
अब, वर्षों बाद, मैं यहां आपके लिए एक संग्रहीत कार्यविधि प्रस्तुत कर रहा हूं जिसका उद्देश्य इस प्रश्न का उत्तर देना है कि "SQL तालिका में डुप्लिकेट रिकॉर्ड कैसे हटाएं?"। कोई भी डीबीए बहुत अधिक चिंता किए बिना कुछ हाउसकीपिंग करने के लिए इसका उपयोग कर सकता है।
संग्रहीत प्रक्रिया बनाएं:प्रारंभिक विचार
आपके द्वारा उपयोग किए जाने वाले खाते में इच्छित डेटाबेस में संग्रहीत कार्यविधि बनाने के लिए पर्याप्त विशेषाधिकार होने चाहिए।
इस संग्रहीत कार्यविधि को निष्पादित करने वाले खाते के पास लक्ष्य डेटाबेस तालिका के विरुद्ध चयन और DELETE संचालन करने के लिए पर्याप्त विशेषाधिकार होने चाहिए।
यह संग्रहीत कार्यविधि उन डेटाबेस तालिकाओं के लिए अभिप्रेत है जिनमें प्राथमिक कुंजी (न ही एक अद्वितीय बाधा) परिभाषित नहीं है। हालांकि, यदि आपकी तालिका में प्राथमिक कुंजी है, तो संग्रहीत प्रक्रिया उन फ़ील्ड को ध्यान में नहीं रखेगी। यह बाकी क्षेत्रों के आधार पर लुकअप और विलोपन करेगा (इसलिए इस मामले में इसका बहुत सावधानी से उपयोग करें)।
संग्रहीत कार्यविधि का उपयोग कैसे करें एसक्यूएल में
इस आलेख में उपलब्ध SP T-SQL कोड को कॉपी और पेस्ट करें। SP को 3 पैरामीटर की उम्मीद है:
@schemaName - यदि लागू हो तो डेटाबेस तालिका स्कीमा का नाम। यदि नहीं - dbo . का प्रयोग करें ।
@tableName - डेटाबेस तालिका का नाम जहां डुप्लिकेट मान संग्रहीत हैं।
@displayOnly - अगर 1 . पर सेट किया गया हो , वास्तविक डुप्लिकेट रिकॉर्ड हटाए नहीं जाएंगे , लेकिन इसके बजाय केवल प्रदर्शित किया जाता है (यदि कोई हो)। डिफ़ॉल्ट रूप से, यह मान 0 . पर सेट होता है जिसका अर्थ है कि वास्तविक विलोपन होगा अगर डुप्लीकेट मौजूद हैं।
SQL सर्वर संग्रहीत कार्यविधि निष्पादन परीक्षण
संग्रहीत प्रक्रिया को प्रदर्शित करने के लिए, मैंने दो अलग-अलग तालिकाएँ बनाई हैं - एक प्राथमिक कुंजी के बिना, और एक प्राथमिक कुंजी के साथ। मैंने इन तालिकाओं में कुछ डमी रिकॉर्ड डाले हैं। आइए देखें कि संग्रहित प्रक्रिया को क्रियान्वित करने से पहले/बाद में मुझे क्या परिणाम मिलते हैं।
प्राथमिक कुंजी वाली SQL तालिका
CREATE TABLE [dbo].[test](
[column1] [varchar](16) NOT NULL,
[column2] [varchar](16) NOT NULL,
[column3] [varchar](16) NOT NULL,
CONSTRAINT [PK_Test] PRIMARY KEY CLUSTERED
(
[column1] ASC,
[column2] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SQL संग्रहीत कार्यविधि उदाहरण रिकॉर्ड
INSERT INTO test VALUES('A','A',1),('A','B',1),('A','C',1),('B','A',2),('B','B',3),('B','C',4)
संग्रहीत कार्यविधि केवल प्रदर्शन के साथ निष्पादित करें
EXEC DBA_DeleteDuplicates @schemaName = 'dbo',@tableName = 'test',@displayOnly = 1
चूंकि कॉलम 1 और कॉलम 2 प्राथमिक कुंजी बनाते हैं, इसलिए डुप्लीकेट का मूल्यांकन गैर-प्राथमिक कुंजी कॉलम के खिलाफ किया जाता है, इस मामले में, कॉलम 3। परिणाम सही है।
केवल प्रदर्शन के बिना संग्रहीत कार्यविधि निष्पादित करें
EXEC DBA_DeleteDuplicates @schemaName = 'dbo',@tableName = 'test',@displayOnly = 0
डुप्लिकेट रिकॉर्ड चले गए हैं।
हालाँकि, आपको इस दृष्टिकोण से सावधान रहना चाहिए क्योंकि रिकॉर्ड की पहली घटना वह है जो कट जाएगी। इसलिए, यदि किसी कारण से आपको किसी विशिष्ट रिकॉर्ड को हटाने की आवश्यकता है, तो आपको अपने विशेष मामले को अलग से निपटाना होगा।
SQL बिना प्राथमिक कुंजी वाली तालिका
CREATE TABLE [dbo].[duplicates](
[column1] [varchar](16) NOT NULL,
[column2] [varchar](16) NOT NULL,
[column3] [varchar](16) NOT NULL
) ON [PRIMARY]
GO
SQL संग्रहित प्रक्रिया उदाहरण रिकॉर्ड
INSERT INTO duplicates VALUES
('John','Smith','Y'),
('John','Smith','Y'),
('John','Smith','N'),
('Peter','Parker','N'),
('Bruce','Wayne','Y'),
('Steve','Rogers','Y'),
('Steve','Rogers','Y'),
('Tony','Stark','N')
संग्रहीत कार्यविधि केवल प्रदर्शन के साथ निष्पादित करें
EXEC DBA_DeleteDuplicates @schemaName = 'dbo',@tableName = 'duplicates',@displayOnly = 1
आउटपुट सही है, वे तालिका में डुप्लिकेट रिकॉर्ड हैं।
केवल प्रदर्शन के बिना संग्रहीत कार्यविधि निष्पादित करें
EXEC DBA_DeleteDuplicates @schemaName = 'dbo',@tableName = 'duplicates',@displayOnly = 0
संग्रहित प्रक्रिया ने अपेक्षा के अनुरूप काम किया है और डुप्लीकेट सफलतापूर्वक साफ हो गए हैं।
विशेष मामले SQL में इस संग्रहीत कार्यविधि के लिए
यदि आपके द्वारा निर्दिष्ट स्कीमा या तालिका आपके डेटाबेस में मौजूद नहीं है, तो संग्रहीत प्रक्रिया आपको सूचित करेगी, और स्क्रिप्ट इसके निष्पादन को समाप्त कर देगी।
यदि आप स्कीमा नाम को खाली छोड़ देते हैं, तो स्क्रिप्ट आपको सूचित करेगी और उसका निष्पादन समाप्त कर देगी।
यदि आप तालिका का नाम खाली छोड़ देते हैं, तो स्क्रिप्ट आपको सूचित करेगी और उसका निष्पादन समाप्त कर देगी।
यदि आप किसी तालिका के विरुद्ध संग्रहीत कार्यविधि निष्पादित करते हैं जिसमें कोई डुप्लीकेट नहीं है और @displayOnly bit को सक्रिय करें , आपको एक खाली परिणाम सेट मिलेगा।
SQL सर्वर संग्रहित प्रक्रिया:पूरा कोड
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author : Alejandro Cobar
-- Create date: 2021-06-01
-- Description: SP to delete duplicate rows in a table
-- =============================================
CREATE PROCEDURE DBA_DeleteDuplicates
@schemaName VARCHAR(128),
@tableName VARCHAR(128),
@displayOnly BIT = 0
AS
BEGIN
SET NOCOUNT ON;
IF LEN(@schemaName) = 0
BEGIN
PRINT 'You must specify the schema of the table!'
RETURN
END
IF LEN(@tableName) = 0
BEGIN
PRINT 'You must specify the name of the table!'
RETURN
END
IF EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = @schemaName AND TABLE_NAME = @tableName)
BEGIN
DECLARE @pkColumnName VARCHAR(128);
DECLARE @columnName VARCHAR(128);
DECLARE @sqlCommand VARCHAR(MAX);
DECLARE @columnsList VARCHAR(MAX);
DECLARE @pkColumnsList VARCHAR(MAX);
DECLARE @pkColumns TABLE(pkColumn VARCHAR(128));
DECLARE @limit INT;
INSERT INTO @pkColumns
SELECT K.COLUMN_NAME
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS C
JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE AS K ON C.TABLE_NAME = K.TABLE_NAME AND C.CONSTRAINT_SCHEMA = K.CONSTRAINT_SCHEMA
WHERE C.CONSTRAINT_TYPE = 'PRIMARY KEY'
AND C.CONSTRAINT_SCHEMA = @schemaName AND C.TABLE_NAME = @tableName
IF((SELECT COUNT(*) FROM @pkColumns) > 0)
BEGIN
DECLARE pk_cursor CURSOR FOR
SELECT * FROM @pkColumns
OPEN pk_cursor
FETCH NEXT FROM pk_cursor INTO @pkColumnName
WHILE @@FETCH_STATUS = 0
BEGIN
SET @pkColumnsList = CONCAT(@pkColumnsList,'',@pkColumnName,',')
FETCH NEXT FROM pk_cursor INTO @pkColumnName
END
CLOSE pk_cursor
DEALLOCATE pk_cursor
SET @pkColumnsList = SUBSTRING(@pkColumnsList,1,LEN(@pkColumnsList)-1)
END
DECLARE columns_cursor CURSOR FOR
SELECT COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = @schemaName AND TABLE_NAME = @tableName AND COLUMN_NAME NOT IN (SELECT pkColumn FROM @pkColumns)
ORDER BY ORDINAL_POSITION;
OPEN columns_cursor
FETCH NEXT FROM columns_cursor INTO @columnName
WHILE @@FETCH_STATUS = 0
BEGIN
SET @columnsList = CONCAT(@columnsList,'',@columnName,',')
FETCH NEXT FROM columns_cursor INTO @columnName
END
CLOSE columns_cursor
DEALLOCATE columns_cursor
SET @columnsList = SUBSTRING(@columnsList,1,LEN(@columnsList)-1)
IF((SELECT COUNT(*) FROM @pkColumns) > 0)
BEGIN
IF(CHARINDEX(',',@columnsList) = 0)
SET @limit = LEN(@columnsList)+1
ELSE
SET @limit = CHARINDEX(',',@columnsList)
SET @sqlCommand = CONCAT('WITH CTE (',@columnsList,',DuplicateCount',')
AS (SELECT ',@columnsList,',',
'ROW_NUMBER() OVER(PARTITION BY ',@columnsList,' ',
'ORDER BY ',SUBSTRING(@columnsList,1,@limit-1),') AS DuplicateCount
FROM [',@schemaName,'].[',@tableName,'])
')
IF @displayOnly = 0
SET @sqlCommand = CONCAT(@sqlCommand,'DELETE FROM CTE WHERE DuplicateCount > 1;')
IF @displayOnly = 1
SET @sqlCommand = CONCAT(@sqlCommand,'SELECT ',@columnsList,',MAX(DuplicateCount) AS DuplicateCount FROM CTE WHERE DuplicateCount > 1 GROUP BY ',@columnsList)
END
ELSE
BEGIN
SET @sqlCommand = CONCAT('WITH CTE (',@columnsList,',DuplicateCount',')
AS (SELECT ',@columnsList,',',
'ROW_NUMBER() OVER(PARTITION BY ',@columnsList,' ',
'ORDER BY ',SUBSTRING(@columnsList,1,CHARINDEX(',',@columnsList)-1),') AS DuplicateCount
FROM [',@schemaName,'].[',@tableName,'])
')
IF @displayOnly = 0
SET @sqlCommand = CONCAT(@sqlCommand,'DELETE FROM CTE WHERE DuplicateCount > 1;')
IF @displayOnly = 1
SET @sqlCommand = CONCAT(@sqlCommand,'SELECT * FROM CTE WHERE DuplicateCount > 1;')
END
EXEC (@sqlCommand)
END
ELSE
BEGIN
PRINT 'Table doesn't exist within this database!'
RETURN
END
END
GO
निष्कर्ष
यदि आप नहीं जानते कि SQL तालिका में डुप्लिकेट रिकॉर्ड कैसे हटाएं, तो इस तरह के टूल आपके लिए सहायक होंगे। कोई भी डीबीए जांच सकता है कि क्या डेटाबेस टेबल हैं जिनके पास उनके लिए प्राथमिक कुंजी (न ही अद्वितीय बाधाएं) नहीं हैं, जो समय के साथ अनावश्यक रिकॉर्ड का ढेर जमा कर सकते हैं (संभावित रूप से भंडारण बर्बाद कर रहे हैं)। बस संग्रहित प्रक्रिया को प्लग एंड प्ले करें, और आप जाने के लिए तैयार हैं।
आप थोड़ा और आगे जा सकते हैं और आपको सूचित करने के लिए एक चेतावनी तंत्र का निर्माण कर सकते हैं कि क्या किसी विशिष्ट तालिका के लिए डुप्लिकेट हैं (इस उपकरण का उपयोग करके कुछ स्वचालन को लागू करने के बाद), जो काफी काम आता है।
डीबीए कार्यों से संबंधित किसी भी चीज़ की तरह, उत्पादन में ट्रिगर खींचने से पहले हमेशा सैंडबॉक्स वातावरण में सब कुछ का परीक्षण करना सुनिश्चित करें। और जब आप ऐसा करते हैं, तो सुनिश्चित करें कि आपके पास उस तालिका का बैकअप है जिस पर आप ध्यान केंद्रित करते हैं।