🧚 Άκου! Το Beekeeper Studio είναι ένα γρήγορο, σύγχρονο και open source GUI για βάσεις δεδομένων Λήψη
7 Ιανουαρίου 2026 Από τον Matthew Rathbone

Η αφαίρεση διπλοτύπων στην SQL σημαίνει ένα από τα δύο: είτε κρύβεις τις επαναλαμβανόμενες γραμμές από το αποτέλεσμα ενός query με DISTINCT, είτε διαγράφεις τα επιπλέον αντίγραφα από τον πίνακα ώστε να μείνει ένα από το καθένα. Τα παραδείγματα λειτουργούν σε PostgreSQL, MySQL, SQLite και SQL Server.

Πώς να αφαιρέσεις διπλότυπα στην SQL

Το SELECT DISTINCT επιστρέφει κάθε συνδυασμό των στηλών που αναφέρεις μία φορά και αφήνει τον πίνακα ανέγγιχτο. Για να καθαρίσεις τον ίδιο τον πίνακα, διάγραψε όλες τις γραμμές εκτός από μία σε κάθε ομάδα διπλοτύπων, συνήθως αυτή με το μικρότερο id:

SELECT DISTINCT column_list FROM table_name;

DELETE FROM table_name
WHERE id NOT IN (
  SELECT id FROM (
    SELECT MIN(id) AS id FROM table_name GROUP BY column_list
  ) AS keepers
);

Εδώ η Maria Lopez καταχωρήθηκε τρεις φορές:

-- Input: customers
-- id | name        | email             | phone
-- ---+-------------+-------------------+---------
-- 1  | Maria Lopez | maria@example.com | 555-0142
-- 2  | Sam Patel   | sam@example.com   | 555-0178
-- 3  | Maria Lopez | maria@example.com | 555-0142
-- 4  | Lena Novak  | lena@example.com  | 555-0121
-- 5  | Maria Lopez | maria@example.com | 555-0142

SELECT DISTINCT name, email, phone
FROM customers
ORDER BY name;

-- Output:
-- name        | email             | phone
-- ------------+-------------------+---------
-- Lena Novak  | lena@example.com  | 555-0121
-- Maria Lopez | maria@example.com | 555-0142
-- Sam Patel   | sam@example.com   | 555-0178

DELETE FROM customers
WHERE id NOT IN (
  SELECT id FROM (
    SELECT MIN(id) AS id FROM customers GROUP BY name, email, phone
  ) AS keepers
);

-- Output (customers after the DELETE):
-- id | name        | email             | phone
-- ---+-------------+-------------------+---------
-- 1  | Maria Lopez | maria@example.com | 555-0142
-- 2  | Sam Patel   | sam@example.com   | 555-0178
-- 4  | Lena Novak  | lena@example.com  | 555-0121

Κανόνες που πρέπει να ξέρεις

  • Όρισε τις στήλες που κάνουν δύο γραμμές διπλότυπες. Άφησε έξω το id και ό,τι άλλο διαφέρει πάντα, όπως ένα timestamp created_at. Οι γραμμές που διαφέρουν σε οποιαδήποτε από τις στήλες αυτές διατηρούνται όλες.
  • Το περιτύλιγμα SELECT id FROM (...) AS keepers υπάρχει για τη MySQL, η οποία αλλιώς δεν επιτρέπει σε ένα DELETE να διαβάσει τον ίδιο του τον πίνακα σε subquery: “You can’t specify target table ‘customers’ for update in FROM clause”.
  • Κοίτα πριν διαγράψεις. Τρέξε πρώτα το query με GROUP BY ή ROW_NUMBER() για να δεις τι θα φύγει, και κάνε τη διαγραφή μέσα σε transaction που μπορείς να αναιρέσεις.
  • Σταμάτα νέα διπλότυπα με ένα unique index μόλις καθαρίσει ο πίνακας:
CREATE UNIQUE INDEX customers_email_key ON customers (email);

INSERT INTO customers VALUES (6, 'Maria Lopez', 'maria@example.com', '555-0142');
-- ERROR: duplicate key value violates unique constraint "customers_email_key"

Εναλλακτική σύνταξη

Σε κώδικα SQL Server θα δεις συχνά τα αντίγραφα να αριθμούνται σε ένα CTE και να διαγράφονται μέσω αυτού, κάτι που επιτρέπει μόνο ο SQL Server. Στον αρχικό πίνακα customers:

-- SQL Server
WITH numbered AS (
  SELECT *, ROW_NUMBER() OVER (
    PARTITION BY name, email, phone ORDER BY id
  ) AS row_num
  FROM customers
)
DELETE FROM numbered WHERE row_num > 1;

-- Output (customers after the DELETE):
-- id | name        | email             | phone
-- ---+-------------+-------------------+---------
-- 1  | Maria Lopez | maria@example.com | 555-0142
-- 2  | Sam Patel   | sam@example.com   | 555-0178
-- 4  | Lena Novak  | lena@example.com  | 555-0121

Για να συνδυάσεις δύο queries χωρίς επαναλαμβανόμενες γραμμές, χρησιμοποίησε UNION, που αφαιρεί τα διπλότυπα, αντί για UNION ALL, που τα κρατά:

SELECT 'apple' AS fruit UNION ALL SELECT 'apple';

-- Output:
-- fruit
-- -----
-- apple
-- apple

SELECT 'apple' AS fruit UNION SELECT 'apple';
-- Output: apple

Πότε πρέπει να αφαιρείς διπλότυπα;

Μερικές φορές χρειάζεται απλώς να κρύψεις τις επαναλήψεις σε ένα αποτέλεσμα, και άλλες φορές πρέπει να καθαρίσεις τον ίδιο τον πίνακα. Αυτά είναι τα συνηθισμένα βήματα, από τον έλεγχο μέχρι τη διαγραφή.

Εμφάνισε κάθε τιμή μία φορά

Για μια αναφορά, ένα dropdown ή έναν γρήγορο έλεγχο του τι περιέχει μια στήλη, το SELECT DISTINCT αφαιρεί τις επαναλήψεις από το αποτέλεσμα και αφήνει τον πίνακα όπως είναι.

Μέτρα τα αντίγραφα πριν διαγράψεις

Κάνε group by στις στήλες που ορίζουν ένα διπλότυπο και κράτα τις ομάδες με HAVING COUNT(*) > 1. Έτσι βλέπεις τι είναι διπλότυπο και πόσες φορές, πριν αφαιρεθεί οτιδήποτε. Ο οδηγός εύρεσης διπλοτύπων στην SQL καλύπτει περισσότερους τρόπους ελέγχου.

Διάλεξε ποιο αντίγραφο θα κρατήσεις

Το ROW_NUMBER() αριθμεί τις γραμμές σε κάθε ομάδα διπλοτύπων. Το ORDER BY μέσα στο OVER (...) αποφασίζει ποια γραμμή παίρνει το 1 και μένει: η παλαιότερη, η νεότερη ή η πιο πλήρης.

Διάγραψε τα επιπλέον αντίγραφα

Μόλις ξέρεις ποια γραμμή θα κρατήσεις, διάγραψε τις υπόλοιπες. Για να κρατήσεις τη νεότερη γραμμή αντί για την παλαιότερη, αρίθμησε τις γραμμές κατά ημερομηνία, με τη νεότερη πρώτη, και διάγραψε ό,τι έχει αριθμό πάνω από 1.

Πραγματικά παραδείγματα αφαίρεσης διπλοτύπων

Κάθε χώρα και μεταφορέας με τους οποίους στέλνεις

Το DISTINCT εφαρμόζεται σε ολόκληρη τη γραμμή των επιλεγμένων στηλών, οπότε ο Καναδάς εμφανίζεται μία φορά για κάθε μεταφορέα:

-- Input: shipments
-- order_id | country | carrier
-- ---------+---------+--------
-- 1001     | Canada  | UPS
-- 1002     | Germany | DHL
-- 1003     | Canada  | FedEx
-- 1004     | Canada  | UPS
-- 1005     | Germany | DHL

SELECT DISTINCT country, carrier
FROM shipments
ORDER BY country, carrier;

-- Output:
-- country | carrier
-- --------+--------
-- Canada  | FedEx
-- Canada  | UPS
-- Germany | DHL

Διευθύνσεις email που διαφέρουν μόνο σε πεζά/κεφαλαία

Κάνε group by στο email με πεζά, ώστε τα Jon@Example.com και jon@example.com να μετρούν ως αντίγραφα. (Η MySQL και ο SQL Server αγνοούν ήδη τα πεζά/κεφαλαία από προεπιλογή, και το LOWER() δεν βλάπτει εκεί.)

-- Input: accounts
-- id | email
-- ---+----------------------
-- 1  | Ana.Silva@example.com
-- 2  | jon@example.com
-- 3  | ana.silva@example.com
-- 4  | Jon@Example.com
-- 5  | mei@example.com

SELECT LOWER(email) AS email, COUNT(*) AS copies
FROM accounts
GROUP BY LOWER(email)
HAVING COUNT(*) > 1
ORDER BY email;

-- Output:
-- email                 | copies
-- ----------------------+-------
-- ana.silva@example.com | 2
-- jon@example.com       | 2

Κράτα το αντίγραφο που έχει αριθμό τηλεφώνου

Ταξινόμησε πρώτα τις γραμμές που έχουν τηλέφωνο και μετά κατά id, ώστε η πιο πλήρης γραμμή σε κάθε ομάδα να είναι το νούμερο 1:

-- Input: contacts
-- id | email            | phone
-- ---+------------------+---------
-- 1  | ravi@example.com | NULL
-- 2  | ravi@example.com | 555-0110
-- 3  | ines@example.com | 555-0133
-- 4  | ines@example.com | NULL

SELECT
  id,
  email,
  phone,
  ROW_NUMBER() OVER (
    PARTITION BY email
    ORDER BY CASE WHEN phone IS NULL THEN 1 ELSE 0 END, id
  ) AS row_num
FROM contacts
ORDER BY email, row_num;

-- Output:
-- id | email            | phone    | row_num
-- ---+------------------+----------+--------
-- 3  | ines@example.com | 555-0133 | 1
-- 4  | ines@example.com | NULL     | 2
-- 2  | ravi@example.com | 555-0110 | 1
-- 1  | ravi@example.com | NULL     | 2

Η διαγραφή των γραμμών με αριθμό 2 και πάνω (ids 1 και 4) αφήνει μία πλήρη επαφή ανά email.

Διάγραψε ακριβή αντίγραφα από πίνακα χωρίς id

Όταν τα αντίγραφα είναι ίδια σε κάθε στήλη, δεν υπάρχει id για να κρατήσεις το μικρότερο. Αντέγραψε τις μοναδικές γραμμές σε νέο πίνακα και βάλ' τον στη θέση του παλιού. Πρόσθεσε ξανά τα indexes και τα constraints που είχε ο παλιός πίνακας, γιατί το αντίγραφο δεν τα διατηρεί:

-- Input: page_views
-- url      | viewed_at
-- ---------+--------------------
-- /pricing | 2026-10-01 09:00:00
-- /pricing | 2026-10-01 09:00:00
-- /docs    | 2026-10-01 09:05:00
-- /pricing | 2026-10-01 09:00:00

-- In SQL Server, use SELECT DISTINCT * INTO page_views_clean FROM page_views,
-- then EXEC sp_rename 'page_views_clean', 'page_views'
CREATE TABLE page_views_clean AS SELECT DISTINCT * FROM page_views;
DROP TABLE page_views;
ALTER TABLE page_views_clean RENAME TO page_views;

-- Output (page_views afterwards):
-- url      | viewed_at
-- ---------+--------------------
-- /pricing | 2026-10-01 09:00:00
-- /docs    | 2026-10-01 09:05:00

Περισσότερα για την αφαίρεση διπλοτύπων

Σε αυτό το blog:

Επίσημη τεκμηρίωση:

Το Beekeeper Studio είναι ένα δωρεάν & open source GUI για βάσεις δεδομένων

Το καλύτερο εργαλείο για SQL queries & επεξεργασία που έχω χρησιμοποιήσει ποτέ. Μου δίνει ό,τι χρειάζομαι για να διαχειρίζομαι τη βάση δεδομένων μου. - ⭐⭐⭐⭐⭐ Mit

Το Beekeeper Studio είναι γρήγορο, εύχρηστο και κατανοητό με την πρώτη ματιά. Υποστηρίζει πάρα πολλές βάσεις δεδομένων και δουλεύει άψογα σε Windows, Mac και Linux.

Η έκδοση του Beekeeper για Linux έχει 100% όλες τις λειτουργίες, χωρίς εκπτώσεις και χωρίς συμβιβασμούς.

Τι λένε οι χρήστες για το Beekeeper Studio

★★★★★
"Το Beekeeper Studio αντικατέστησε εντελώς την παλιά μου ροή εργασίας με SQL. Είναι γρήγορο, εύχρηστο και κάνει τη δουλειά με βάσεις δεδομένων ξανά ευχάριστη."
— Alex K., Database Developer
★★★★★
"Έχω δοκιμάσει πολλά GUI για βάσεις δεδομένων, αλλά το Beekeeper βρίσκει την τέλεια ισορροπία ανάμεσα σε λειτουργίες και απλότητα. Απλώς δουλεύει."
— Sarah M., Full Stack Engineer

Έτοιμος να βελτιώσεις τη ροή εργασίας σου με SQL;

download Δωρεάν λήψη