Database
 sql >> डेटाबेस >  >> RDS >> Database

SQL तालिका में डुप्लिकेट रिकॉर्ड्स को हटाने के लिए संग्रहीत प्रक्रिया

कभी-कभी डीबीए के रूप में हमारे रन के दौरान, हम कम से कम एक टेबल पर आते हैं जो डुप्लिकेट रिकॉर्ड से भरी होती है। भले ही तालिका में प्राथमिक कुंजी हो (ज्यादातर मामलों में एक स्वत:वृद्धिशील), शेष फ़ील्ड में डुप्लिकेट मान हो सकते हैं।

हालांकि, 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 तालिका में डुप्लिकेट रिकॉर्ड कैसे हटाएं, तो इस तरह के टूल आपके लिए सहायक होंगे। कोई भी डीबीए जांच सकता है कि क्या डेटाबेस टेबल हैं जिनके पास उनके लिए प्राथमिक कुंजी (न ही अद्वितीय बाधाएं) नहीं हैं, जो समय के साथ अनावश्यक रिकॉर्ड का ढेर जमा कर सकते हैं (संभावित रूप से भंडारण बर्बाद कर रहे हैं)। बस संग्रहित प्रक्रिया को प्लग एंड प्ले करें, और आप जाने के लिए तैयार हैं।

आप थोड़ा और आगे जा सकते हैं और आपको सूचित करने के लिए एक चेतावनी तंत्र का निर्माण कर सकते हैं कि क्या किसी विशिष्ट तालिका के लिए डुप्लिकेट हैं (इस उपकरण का उपयोग करके कुछ स्वचालन को लागू करने के बाद), जो काफी काम आता है।

डीबीए कार्यों से संबंधित किसी भी चीज़ की तरह, उत्पादन में ट्रिगर खींचने से पहले हमेशा सैंडबॉक्स वातावरण में सब कुछ का परीक्षण करना सुनिश्चित करें। और जब आप ऐसा करते हैं, तो सुनिश्चित करें कि आपके पास उस तालिका का बैकअप है जिस पर आप ध्यान केंद्रित करते हैं।


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. क्या आप क्रमबद्ध हैं? टी-एसक्यूएल विंडो ऑर्डरिंग से संबंधित टिप्स

  2. एसक्यूएल नहीं ऑपरेटर

  3. JDBC स्टेटमेंट और तैयार स्टेटमेंट के बीच अंतर

  4. आईआरआई कार्यक्षेत्र में डेटा प्रतिकृति

  5. VDP उन्नत SQL एजेंट के साथ SQL डेटाबेस का बैकअप लेना