Ανταλλάξτε το μοναδικό δείκτη τιμών στήλη στη βάση δεδομένων

ψήφοι
47

Έχω έναν πίνακα βάσης δεδομένων και ένα από τα πεδία (όχι το πρωτεύον κλειδί) έχει ένα μοναδικό ευρετήριο για αυτό. Τώρα θέλω να ανταλλάξουν τιμές στη στήλη αυτή για δύο σειρές. Πώς θα μπορούσε να γίνει αυτό; Δύο αμυχές ξέρω είναι:

  1. Διαγραφή δύο σειρές και τα τοποθετήστε ξανά
  2. Ενημέρωση σειρές με κάποια άλλη αξία και ανταλλαγής και στη συνέχεια να ενημερώσετε την πραγματική αξία.

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

Δημοσιεύθηκε 03/08/2008 στις 10:55
πηγή χρήστη
Σε άλλες γλώσσες...                            


12 απαντήσεις

ψήφοι
21

Η μαγική λέξη είναι deferrable εδώ:

DROP TABLE ztable CASCADE;
CREATE TABLE ztable
    ( id integer NOT NULL PRIMARY KEY
    , payload varchar
    );
INSERT IGNORE  INTO ztable(id,payload) VALUES (1,'one' ), (2,'two' ), (3,'three' );
SELECT * FROM ztable;


    -- This works, because there is no constraint
UPDATE ztable t1
SET payload=t2.payload
FROM ztable t2
WHERE t1.id IN (2,3)
AND t2.id IN (2,3)
AND t1.id <> t2.id
    ;
SELECT * FROM ztable;

ALTER TABLE ztable ADD CONSTRAINT OMG_WTF UNIQUE (payload)
    DEFERRABLE INITIALLY DEFERRED
    ;

    -- This should also work, because the constraint 
    -- is deferred until "commit time"
UPDATE ztable t1
SET payload=t2.payload
FROM ztable t2
WHERE t1.id IN (2,3)
AND t2.id IN (2,3)
AND t1.id <> t2.id
    ;
SELECT * FROM ztable;

ΑΠΟΤΕΛΕΣΜΑ:

DROP TABLE
NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "ztable_pkey" for table "ztable"
CREATE TABLE
INSERT IGNORE  0 3
 id | payload
----+---------
  1 | one
  2 | two
  3 | three
(3 rows)

UPDATE 2
 id | payload
----+---------
  1 | one
  2 | three
  3 | two
(3 rows)

NOTICE:  ALTER TABLE / ADD UNIQUE will create implicit index "omg_wtf" for table "ztable"
ALTER TABLE
UPDATE 2
 id | payload
----+---------
  1 | one
  2 | two
  3 | three
(3 rows)
Απαντήθηκε 15/09/2012 στις 13:38
πηγή χρήστη

ψήφοι
8

Νομίζω ότι θα πρέπει να πάμε για λύση 2. Δεν υπάρχει η λειτουργία «μετάθεσης» σε οποιαδήποτε SQL παραλλαγή ξέρω.

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

Αλλά με λίγα λόγια: δεν υπάρχει άλλη λύση από αυτές που παρέχονται.

Απαντήθηκε 03/08/2008 στις 13:26
πηγή χρήστη

ψήφοι
5

Υπάρχει και μια άλλη προσέγγιση που συνεργάζεται με τον SQL Server: χρησιμοποιήστε ένα πίνακα temp ενταχθούν σ 'αυτήν τη δήλωση UPDATE σας.

Το πρόβλημα προκαλείται από την κατοχή δύο σειρές με την ίδια τιμή την ίδια στιγμή , αλλά αν ενημερώσετε δύο σειρές ταυτόχρονα (σε νέες, μοναδικές τιμές τους), δεν υπάρχει καμία παραβίαση περιορισμών.

Ψευδοκώδικας:

-- setup initial data values:
insert into data_table(id, name) values(1, 'A')
insert into data_table(id, name) values(2, 'B')

-- create temp table that matches live table
select top 0 * into #tmp_data_table from data_table

-- insert records to be swapped
insert into #tmp_data_table(id, name) values(1, 'B')
insert into #tmp_data_table(id, name) values(2, 'A')

-- update both rows at once! No index violations!
update data_table set name = #tmp_data_table.name
from data_table join #tmp_data_table on (data_table.id = #tmp_data_table.id)

Χάρη στην Rich H για αυτήν την τεχνική. - Mark

Απαντήθηκε 04/04/2012 στις 20:40
πηγή χρήστη

ψήφοι
5

Σε συνέχεια της απάντησης του Andy Irving του

Αυτό λειτούργησε για μένα (για SQL Server 2005) σε μια παρόμοια κατάσταση, όπου έχω ένα σύνθετο κλειδί και θα πρέπει να ανταλλάξουν ένα πεδίο το οποίο είναι μέρος του μοναδικό περιορισμό.

κλειδί: PID, REC 1 LNUM: 10, 0 rec2: 10, 1 rec3: 10, 2

και θα πρέπει να ανταλλάξουν LNUM έτσι ώστε το αποτέλεσμα να είναι

κλειδί: PID, REC 1 LNUM: 10, 1 rec2: 10, 2 rec3: 10, 0

η SQL που απαιτούνται:

UPDATE    DOCDATA    
SET       LNUM = CASE LNUM
              WHEN 0 THEN 1
              WHEN 1 THEN 2 
              WHEN 2 THEN 0 
          END
WHERE     (pID = 10) 
  AND     (LNUM IN (0, 1, 2))
Απαντήθηκε 10/12/2008 στις 13:19
πηγή χρήστη

ψήφοι
2

Εχω το ίδιο πρόβλημα. Εδώ είναι προτεινόμενη προσέγγιση μου στην PostgreSQL. Στην περίπτωσή μου, το μοναδικό δείκτη μου είναι μια τιμή ακολουθίας, που ορίζει ρητά το χρήστη προκειμένου για σειρές μου. Ο χρήστης θα ανακατέψει σειρές γύρω σε ένα web-app, στη συνέχεια, να υποβάλουν τις αλλαγές.

Είμαι σχεδιάζει να προσθέσει ένα «πριν» σκανδάλη. Σε αυτή την σκανδάλη, κάθε φορά που ενημερώνεται μοναδική τιμή δείκτη μου, θα κοιτάξουμε να δούμε αν υπάρχει άλλη σειρά διαθέτει ήδη νέα τιμή μου. Αν ναι, θα τους δώσω παλιά τιμή μου, και να κλέψει αποτελεσματικά την αξία από αυτούς.

Ελπίζω ότι η PostgreSQL θα μου επιτρέψετε να κάνω αυτό το ανακάτεμα της πριν σκανδάλη.

Θα πάρω μετά πίσω και να σας ενημερώσουμε για τα διανυθέντα χιλιόμετρα μου.

Απαντήθηκε 24/06/2009 στις 04:58
πηγή χρήστη

ψήφοι
2

Υποθέτοντας ότι γνωρίζετε το PK των δύο γραμμών που θέλετε να ενημερώσετε ... Αυτό λειτουργεί σε SQL Server, δεν μπορούμε να μιλάμε για άλλα προϊόντα. SQL είναι (υποτίθεται ότι είναι) ατομικό σε επίπεδο δήλωση:

CREATE TABLE testing
(
    cola int NOT NULL,
    colb CHAR(1) NOT NULL
);

CREATE UNIQUE INDEX UIX_testing_a ON testing(colb);

INSERT IGNORE  INTO testing VALUES (1, 'b');
INSERT IGNORE  INTO testing VALUES (2, 'a');

SELECT * FROM testing;

UPDATE testing
SET colb = CASE cola WHEN 1 THEN 'a'
                WHEN 2 THEN 'b'
                END
WHERE cola IN (1,2);

SELECT * FROM testing;

έτσι θα πάει από:

cola    colb
------------
1       b
2       a

προς το:

cola    colb
------------
1       a
2       b
Απαντήθηκε 16/09/2008 στις 15:57
πηγή χρήστη

ψήφοι
2

Πιστεύω επίσης ότι # 2 είναι το καλύτερο στοίχημα, αν και θα ήθελα να είναι σίγουρος για να το τυλίξετε σε μια συναλλαγή σε περίπτωση που κάτι πάει στραβά μέσα ενημέρωσης.

Μια εναλλακτική λύση (από τη στιγμή που ζήτησε) την επικαιροποίηση των τιμών μοναδικό ευρετήριο με διαφορετικές τιμές θα ήταν να ενημερώσετε όλες τις άλλες τιμές στις σειρές με εκείνο της άλλης σειράς. Με αυτόν τον τρόπο σημαίνει ότι θα μπορούσε να αφήσει τις τιμές μοναδικό ευρετήριο μόνο του, και στο τέλος, θα καταλήξετε με τα δεδομένα που θέλετε. Να είστε προσεκτικοί αν και, σε περίπτωση που κάποια άλλα τραπέζι αναφορές αυτού του πίνακα σε ένα ξένο κλειδί της σχέσης, ότι όλες οι σχέσεις της DB παραμένουν άθικτα.

Απαντήθηκε 03/08/2008 στις 14:22
πηγή χρήστη

ψήφοι
1

1) αλλάξετε τα αναγνωριστικά για το όνομα

id    student 

1     Abbot   
2     Doris  
3     Emerson 
4     Green  
5     Jeames  

Για την είσοδο του δείγματος, η έξοδος είναι:

φοιτητής id

1     Doris   
2     Abbot   
3     Green   
4     Emerson 
5     Jeames  

«Σε περίπτωση αριθμό n των γραμμών πώς θα διαχειριστεί ......»

Απαντήθηκε 06/11/2018 στις 08:56
πηγή χρήστη

ψήφοι
1

Για Oracle υπάρχει μια επιλογή, αναβλήθηκε, αλλά θα πρέπει να το προσθέσετε σε περιορισμό σας.

SET CONSTRAINT emp_no_fk_par DEFERRED; 

Για να αναβάλει όλους τους περιορισμούς που είναι deferrable όλη τη διάρκεια της συνεδρίας, μπορείτε να χρησιμοποιήσετε το ALTER ΣΥΝΟΔΟΣ SET περιορισμούς = ΑΝΑΒΑΛΛΟΜΕΝΟΣ δήλωση.

Πηγή

Απαντήθηκε 27/04/2016 στις 14:15
πηγή χρήστη

ψήφοι
1

Στον SQL Server, η δήλωση MERGE να ενημερώσετε σειρές που κανονικά θα σπάσει ένα μοναδικό κλειδί / INDEX. (Ακριβώς δοκιμαστεί αυτό επειδή ήμουν περίεργος.)

Ωστόσο, θα πρέπει να χρησιμοποιήσετε ένα temp πίνακα / μεταβλητή για την προμήθεια MERGE w / τις αναγκαίες σειρές.

Απαντήθηκε 20/04/2012 στις 20:12
πηγή χρήστη

ψήφοι
1

Η Oracle έχει δώσει αναβολή από τον έλεγχο της ακεραιότητας που λύνει ακριβώς αυτό, αλλά δεν είναι διαθέσιμα είτε σε SQL Server ή MySQL.

Απαντήθηκε 19/03/2010 στις 20:29
πηγή χρήστη

ψήφοι
0

Συνήθως σκεφτείτε μια τιμή που καμία απολύτως δείκτη στο τραπέζι μου θα μπορούσε να έχει. Συνήθως - για τις μοναδικές τιμές της στήλης - είναι πραγματικά εύκολο. Για παράδειγμα, για τιμές της στήλης «θέσης» (πληροφορίες σχετικά με τη σειρά αρκετών στοιχείων) είναι 0.

Στη συνέχεια, μπορείτε να αντιγράψετε τιμή Α σε μια μεταβλητή, τον ενημερώνει με τιμή Β και, στη συνέχεια, ορίστε την τιμή B από την μεταβλητή σας. Δύο ερωτήματα, ξέρω ότι δεν είναι καλύτερη λύση όμως.

Απαντήθηκε 18/03/2017 στις 18:00
πηγή χρήστη

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more