SQLite veritabanı tablosundaki bir sütunu nasıl yeniden adlandırabilirim?


296

Bir SQLite veritabanındaki bazı tablolarda birkaç sütun yeniden adlandırmak gerekir. Benzer bir sorunun daha önce stackoverflow üzerinde sorulduğunu biliyorum , ancak genel olarak SQL içindi ve SQLite vakası belirtilmedi.

ALTER TABLE için SQLite belgelerinden , böyle bir şeyi "kolayca" (yani tek bir ALTER TABLE deyimi) yapmanın mümkün olmadığını derliyorum.

Birisinin SQLite ile böyle bir şey yapmanın genel bir SQL yolunu bildiğini merak ediyordum.


Bunu sqlite için db tarayıcısını kullanarak kolayca yapabilirsiniz
Matt G

1
Lütfen bu yanıtı kabul edilmiş olarak işaretlemeyi düşünün stackoverflow.com/a/52346199/124486
Evan Carroll

Yanıtlar:


66

Bu sadece 2018-09-15 (3.25.0) ile düzeltildi

Geliştirmeleri ALTER TABLEkomut:

  • Tabloyu kullanarak ALTER TABLEtablodaki sütunları yeniden adlandırma desteği ekleyin RENAME COLUMN oldname TO newname.
  • Tablo yeniden adlandırma özelliğini, yeniden adlandırılan tabloya yapılan tetikleyicileri ve görünümleri de güncelleştirecek şekilde düzeltin.

Yeni sözdizimini aşağıda belgelenmiştir. ALTER TABLE

RENAME COLUMN TOSözdizimi yeni sütunlu isme masa masa adının kolon-adını değiştirir. Sütun adı hem tablo tanımının kendisinde hem de sütuna başvuran tüm dizinler, tetikleyiciler ve görünümlerde değiştirilir. Sütun adı değişikliği bir tetikleyicide veya görünümde anlamsal bir belirsizlikle sonuçlanırsa, RENAME COLUMNhatayla başarısız olur ve değişiklik uygulanmaz.

resim açıklamasını buraya girin Görüntü kaynağı: https://www.sqlite.org/images/syntax/alter-table-stmt.gif

Misal:

CREATE TABLE tab AS SELECT 1 AS c;

SELECT * FROM tab;

ALTER TABLE tab RENAME COLUMN c to c_new;

SELECT * FROM tab;

db-fiddle.com demosu


Android Desteği

Yazma itibariyle, Android'in API 27'si SQLite paketi sürüm 3.19'u kullanıyor .

Android'in kullandığı mevcut sürüme ve bu güncellemenin SQLite'ın 3.25.0 sürümünde geldiğine dayanarak, Android için destek eklenmeden önce biraz bekleyin (yaklaşık API 33) olduğunu söyleyebilirim.

Ve o zaman bile, API 33'ten daha eski sürümleri desteklemeniz gerekiyorsa, bunu kullanamayacaksınız.


8
Bir Android geçişi için uyguluyorum ve ne yazık ki IntelliJ geçerli bir SQL komutu olmadığına dair bir uyarı gösteriyor. database.execSQL("ALTER TABLE content RENAME COLUMN archiveCount TO dismissCount"). COLUM kırmızı renkte yanıyor ve TO beklenen, 'COLUMN' var diyor . Ne yazık ki Android hala SQLite 3.19 sürümünde , bu yüzden bu benim için çalışmıyor.
Adam Hurwitz

1
düzenlendi: system.data.sqlite.org/index.html/doc/trunk/www/faq.wiki#q1 üzerinde , 1.0.109.x) aslında SQLite 3.24 ve System.Data.SQLite kullandığını buldum SQLite 3.25 kullanan bu ay relased edildi.
rychlmoj

1
FYI, maalesef bu henüz Android'in SQLite kütüphanesi tarafından uygulanmadı . Umarım yakında güncellenir.
Adam Hurwitz

3
Android Destek için başkalarının umutlarını artırmalarını önleyen bir bölüm ekledim. Android 27'nin şu anki SQLite 3.19 kullanımına dayanarak, bu özellik Android'e eklenmeden önce yaklaşık API 33'e kadar beklememiz gerekecek ve o zaman bile sadece en son sürümlerde desteklenecek. İç çekmek.
Joshua Pinter

1
@JoshuaPinter Cevabımı uzattığınız için teşekkürler.
Lukasz Szozda

448

Bir tablonuz olduğunu ve "colb" ifadesini "col_b" olarak yeniden adlandırmanız gerektiğini varsayalım:

Önce eski tabloyu yeniden adlandırın:

ALTER TABLE orig_table_name RENAME TO tmp_table_name;

Ardından, eski tabloyu temel alan ancak güncellenmiş sütun adıyla yeni tablo oluşturun:

CREATE TABLE orig_table_name (
  col_a INT
, col_b INT
);

Ardından içerikleri orijinal tablodan kopyalayın.

INSERT INTO orig_table_name(col_a, col_b)
SELECT col_a, colb
FROM tmp_table_name;

Son olarak, eski masayı bırakın.

DROP TABLE tmp_table_name;

Bütün bunları bir BEGIN TRANSACTION;ve COMMIT;içine sarmak da muhtemelen iyi bir fikirdir.


51
Ve endekslerinizi unutmayın.
Tom Mayfield

11
Daha da önemlisi yukarıdaki örnek kodda bir işlem eksik. Yeniden adlandırma işleminin başarıyla tamamlandığından veya hiç tamamlanmadığından emin olmak için her şeyi bir BEGIN / END (veya ROLLBACK) içine sarmalısınız.
Roger Binns

4
Android'de bunu yapmak isteyen herkes SQLiteDatabase.beginTransaction ()
bmaupin

7
Yanıtta kodda indeksleri kopyalayan hiçbir şey yok. Boş bir tablo oluşturmak ve içine veri koymak sadece yapıyı ve verileri kopyalar. Meta veriler (dizinler, yabancı anahtarlar, kısıtlamalar vb.) İstiyorsanız, değiştirilen tabloda bunları oluşturmak için ifadeler de yayınlamanız gerekir.
Tom Mayfield

17
SQLite .schemakomutu, CREATE TABLEmevcut tabloyu oluşturan ifadeyi göstermek için kullanışlıdır . Çıktısını alabilir, gerektiği gibi değiştirebilir ve yeni tablo oluşturmak için çalıştırabilirsiniz. Bu komut aynı zamanda CREATE INDEXThomas'ın endişelerini de içermesi gereken endeksleri oluşturmak için gerekli komutları gösterir . Elbette, herhangi bir şeyi değiştirmeden önce bu komutu çalıştırdığınızdan emin olun.
Mike DeSimone

56

Etrafa baktığımda, SQLite için DB Browser adlı bir çoklu platform (Linux | Mac | Windows) grafik aracını buldum, bu da gerçekten sütunları çok kullanıcı dostu bir şekilde yeniden adlandırmaya izin veriyor!

Düzenle | Tabloyu Değiştir | Tablo Seçin | Alanı Düzenle. Tık Tık! İşte bu kadar!

Bununla birlikte, birisi bunu yapmanın programlı bir yolunu paylaşmak isterse, bilmek beni mutlu eder!


1
Aynı şeyi yapan bir Firefox eklentisi de var, Yeniden adlandırmak istediğiniz sütuna sağ tıklayın ve "Sütunu Düzenle" yi seçin.
Jacob Hacker

1
OpenSUSE içinde bile, bir paket olarak mevcuttur: software.opensuse.org/package/sqlitebrowser

Çok oyu olması garip. Burada programlamadan bahsediyoruz (kod). Bu cevabı neden buraya gönderdiniz?
user25

2
Sorumun koduyla nasıl yapılacağından bahsetmiyorum. Ben sadece bir SQLite DB bir sütun yeniden adlandırmak bilmek istedim.
joce

@ joce seni seviyorum !!! (bir erkek kardeş gibi) beni içeri aldı, alan değişti. Bir MS Access tablo SQLite ihraç vardı ve alanlardan biri önünde bir basamak vardı: 3YearLetterSent. Visual Studio sınıfı tablodan yaptı ancak alan adının önündeki "3" rakamında boğuldu. Bunu biliyorum, sadece izlemiyordum.
JustJohn

53

ALTER COLUMN olmadığı doğru olsa da, yalnızca sütunu yeniden adlandırmak, NOT NULL kısıtlamasını bırakmak veya veri türünü değiştirmek istiyorsanız, aşağıdaki komut kümesini kullanabilirsiniz:

Not: Bu komutların veritabanınızı bozma potansiyeli vardır, bu nedenle bir yedeğiniz olduğundan emin olun

PRAGMA writable_schema = 1;
UPDATE SQLITE_MASTER SET SQL = 'CREATE TABLE BOOKS ( title TEXT NOT NULL, publication_date TEXT)' WHERE NAME = 'BOOKS';
PRAGMA writable_schema = 0;

Değişiklikleri şemaya yeniden yüklemek için bağlantınızı kapatıp yeniden açmanız veya veritabanını vakumlamanız gerekir.

Örneğin:

Y:\> sqlite3 booktest  
SQLite version 3.7.4  
Enter ".help" for instructions  
Enter SQL statements terminated with a ";"  
sqlite> create table BOOKS ( title TEXT NOT NULL, publication_date TEXT NOT NULL);  
sqlite> insert into BOOKS VALUES ("NULLTEST",null);  
Error: BOOKS.publication_date may not be NULL  
sqlite> PRAGMA writable_schema = 1; 
sqlite> UPDATE SQLITE_MASTER SET SQL = 'CREATE TABLE BOOKS ( title TEXT NOT NULL, publication_date TEXT)' WHERE NAME = 'BOOKS';  
sqlite> PRAGMA writable_schema = 0;  
sqlite> .q  

Y:\> sqlite3 booktest  
SQLite version 3.7.4  
Enter ".help" for instructions  
Enter SQL statements terminated with a ";"  
sqlite> insert into BOOKS VALUES ("NULLTEST",null);  
sqlite> .q  

REFERANSLAR TAKİP EDİN:


pragma
writable_schema Bu pragma açık olduğunda, veritabanının normal UPDATE, INSERT ve DELETE deyimleri kullanılarak değiştirilebildiği SQLITE_MASTER tabloları. Uyarı: Bu pragmanın yanlış kullanımı kolayca bozuk bir veritabanı dosyasına neden olabilir.

alter table
SQLite sınırlı bir ALTER TABLE alt kümesini destekler. SQLite'deki ALTER TABLE komutu, kullanıcının bir tabloyu yeniden adlandırmasına veya var olan bir tabloya yeni bir sütun eklemesine olanak tanır. Bir sütunu yeniden adlandırmak, bir sütunu kaldırmak veya tabloya kısıtlama eklemek veya kaldırmak mümkün değildir.

ALTER MASA SİSTEMİ


3
Tehlikeli, ama yine de muhtemelen en basit cevap imo.
Tek

2
Evet son derece hızlı - Tehlikeli sadece "önce yedek olduğundan emin ol" anlamına gelir
Noah

6
Sqlite dosya biçimi çok basit ve bu yüzden bu işlem geçerlidir. Dosya biçimi bir tablo hakkında yalnızca iki bilgi kümesine sahiptir: Gerçek CREATE TABLE komutu düz metin olarak ve değerleri CREATE komutundaki alanların sırasına göre görünen satırlar. Bu, sqlite kodunun veritabanını açtığı, her CREATE komutunu ayrıştırdığı ve sütun bilgilerini dinamik olarak bellekte oluşturduğu anlamına gelir. Bu nedenle, türlerini veya kısıtlamalarını değiştirseniz bile, CREATE komutunu aynı sayıda sütunla sonuçlanacak şekilde değiştiren herhangi bir komut çalışacaktır.
Thomas Tempelmann

3
@ThomasTempelmann Ancak, veri kümesi tarafından yerine getirilmeyen kısıtlamalar eklenmesi sorunlara neden olur çünkü sorgu planlayıcısı kısıtlamaların geçerli olduğunu varsayar.
fuz26

2
@ThomasTempelmann Sınırlamaları kaldırmak her zaman iyidir. Kısıtlama tüm satırlar tarafından karşılanıyorsa, ancak kesinlikle kontrol etmeniz gerekiyorsa kısıtlama eklemek iyidir.
fuz

18

Son zamanlarda SQLite3 bunu colunms id, lon, lat ile puan adlı bir tablo ile yapmak zorunda kaldı . Yanlışlıkla, tablo içe aktarıldığında, lon sütununda ve viceversa'da saklandığı enlem değerleri , bu nedenle bu sütunları yeniden adlandırmak açık bir düzeltme olacaktır. İşte hile:

create table points_tmp as select id, lon as lat, lat as lon from points;
drop table points;
alter table points_tmp rename to points;

Umarım bu sizin için yararlı olur!


Bu yöntem PK değerini uygun şekilde kopyalamaz ve otomatik olarak gizli satır kimliği sütununu oluşturur. Mutlaka bir sorun değil, ama benim için bir sorun haline geldiğinden belirtmek istedim.
TPoschel

4
"GÜNCELLEME noktaları SET lon = lat, lat = lon;" yapmak daha kolay olmaz mıydı?
kstep

1
Bu cevap işlemi doğru SİPARİŞ'te yapar. Önce geçici tabloyu oluşturun ve doldurun, ardından orijinali yok edin .
Xeoncross

14

Sqlite belgelerinden alıntı :

SQLite sınırlı bir ALTER TABLE alt kümesini destekler. SQLite'deki ALTER TABLE komutu, kullanıcının bir tabloyu yeniden adlandırmasına veya var olan bir tabloya yeni bir sütun eklemesine olanak tanır. Bir sütunu yeniden adlandırmak, bir sütunu kaldırmak veya tabloya kısıtlama eklemek veya kaldırmak mümkün değildir.

Elbette yapabileceğiniz şey, yeni düzen ile yeni bir tablo oluşturmak ve yeni tabloyu SELECT * FROM old_tablealacağınız değerlerle doldurmaktır.


7

Öncelikle, bu beni sürprizle yüzüne tokatlayan şeylerden biri: bir sütunun yeniden adlandırılması tamamen yeni bir tablo oluşturmayı ve verileri eski tablodan yeni tabloya kopyalamayı gerektirir ...

GUI Ben ettik SQLite işlemlerini yapmak indi olduğunu Baz . Yürütülen tüm komutları gösteren şık bir Günlük penceresi var. Base ile bir sütunun yeniden adlandırılması, günlük penceresini gerekli komutlarla doldurur:

Temel günlük penceresi

Bunlar daha sonra kolayca kopyalanabilir ve ihtiyacınız olabilecek yere yapıştırılabilir. Benim için bu bir ActiveAndroid'e geçiş dosyasına. Hoş bir dokunuş da kopyalanan verilerin zaman damgalarını değil sadece SQLite komutlarını içermesidir.

Umarım, bu bazı insanlara zaman kazandırır.


Eğer Bilginize, vardır kullanarak ActiveAndroid , sen atlayabilirsiniz BEGIN TRANSACTION;ve COMMIT;kendisi tarafından ActiveAndroid kolları olarak, bu satırları.
Joshua Pinter

6

DURUM 1: SQLite 3.25.0+

Yalnızca SQLite 3.25.0 Sürümü sütunların yeniden adlandırılmasını destekler. Cihazınız bu gereksinimi karşılıyorsa, işler oldukça basittir. Aşağıdaki sorgu sorununuzu çözecektir:

ALTER TABLE "MyTable" RENAME COLUMN "OldColumn" TO "NewColumn";

DURUM 2: SQLite Eski Sürümler

Biraz zor olabilecek sonucu elde etmek için farklı bir Yaklaşım izlemelisiniz

Örneğin, böyle bir tablonuz varsa:

CREATE TABLE student(Name TEXT, Department TEXT, Location TEXT)

Ve sütunun adını değiştirmek isterseniz Location

1. Adım: Orijinal tabloyu yeniden adlandırın:

ALTER TABLE student RENAME TO student_temp;

2. Adım: Şimdi studentdoğru sütun adıyla yeni bir tablo oluşturun :

CREATE TABLE student(Name TEXT, Department TEXT, Address TEXT)

3. Adım: Verileri orijinal tablodan yeni tabloya kopyalayın:

INSERT INTO student(Name, Department, Address) SELECT Name, Department, Location FROM student_temp;

Not: Yukarıdaki komutun tümü bir satır olmalıdır.

4. Adım: Orijinal tabloyu bırakın:

DROP TABLE student_temp;

Bu dört adımla herhangi bir SQLite tablosunu manuel olarak değiştirebilirsiniz. Ayrıca, yeni tablodaki tüm dizinleri, görüntüleyenleri veya tetikleyicileri de yeniden oluşturmanız gerektiğini unutmayın.


1
Android Studio sqllite veritabanı sürümü 3.29.0 yükseltme nasıl api seviye 28 kullanıyorum.
Nathani Software

SQLite sürümü, Uygulamanın çalıştığı cihaz tarafından tanımlanır. Cihaza bağlıdır.
Febin Mathew

1
Eski sqlite kullanan insanlar için yukarıdaki dört adım önerilmez. Sqlite.org/lang_altertable.html adresindeki "Dikkat" bölümüne bakın .
Jeff

3

<id> tablo sütununu <_id> olarak değiştir

 String LastId = "id";

    database.execSQL("ALTER TABLE " + PhraseContract.TABLE_NAME + " RENAME TO " + PhraseContract.TABLE_NAME + "old");
    database.execSQL("CREATE TABLE " + PhraseContract.TABLE_NAME
    +"("
            + PhraseContract.COLUMN_ID + " INTEGER PRIMARY KEY,"
            + PhraseContract.COLUMN_PHRASE + " text ,"
            + PhraseContract.COLUMN_ORDER  + " text ,"
            + PhraseContract.COLUMN_FROM_A_LANG + " text"
    +")"
    );
    database.execSQL("INSERT INTO " +
            PhraseContract.TABLE_NAME + "("+ PhraseContract.COLUMN_ID +" , "+ PhraseContract.COLUMN_PHRASE + " , "+ PhraseContract.COLUMN_ORDER +" , "+ PhraseContract.COLUMN_FROM_A_LANG +")" +
            " SELECT " + LastId +" , "+ PhraseContract.COLUMN_PHRASE + " , "+ PhraseContract.COLUMN_ORDER +" , "+ PhraseContract.COLUMN_FROM_A_LANG +
            " FROM " + PhraseContract.TABLE_NAME + "old");
    database.execSQL("DROP TABLE " + PhraseContract.TABLE_NAME + "old");

3

İstenen sütun adıyla yeni bir sütun oluşturun: COLNew.

ALTER TABLE {tableName} ADD COLUMN COLNew {type};

Eski COLOld sütununun içeriğini yeni COLNew sütununa kopyalayın.

INSERT INTO {tableName} (COLNew) SELECT {COLOld} FROM {tableName}

Not: yukarıdaki satırda parantez gereklidir.


2

Daha önce de belirtildiği gibi, bunu yapan bir araç SQLite Veritabanı Tarayıcısı vardır. Neyse ki, bu araç kullanıcı veya uygulama tarafından gerçekleştirilen tüm işlemlerin bir kaydını tutar. Bunu bir kez yapmak ve uygulama günlüğüne bakmak, ilgili kodu göreceksiniz. Sorguyu kopyalayın ve gerektiği gibi yapıştırın. Benim için çalıştı. Bu yardımcı olur umarım


2

Resmi belgelerden

Diskteki içeriği hiçbir şekilde etkilemeyen bazı değişiklikler için isteğe bağlı olarak daha basit ve daha hızlı bir yordam kullanılabilir. Aşağıdaki daha basit yordam, CHECK veya FOREIGN KEY veya NOT NULL kısıtlamalarını kaldırmak, sütunları yeniden adlandırmak veya bir sütuna varsayılan değerleri eklemek veya kaldırmak veya değiştirmek için uygundur.

  1. Bir işlem başlatın.

  2. Geçerli şema sürüm numarasını belirlemek için PRAGMA schema_version komutunu çalıştırın. Bu sayı, aşağıdaki 6. adım için gerekli olacaktır.

  3. PRAGMA writable_schema = ON kullanarak şema düzenlemeyi etkinleştirin.

  4. Sqlite_master tablosundaki tablo X tanımını değiştirmek için bir UPDATE deyimi çalıştırın: UPDATE sqlite_master SET sql = ... WHERE type = 'table' AND name = 'X';

    Uyarı: sqlite_master tablosunda böyle bir değişiklik yapılması, sözdizimi hatası içeriyorsa veritabanını bozuk ve okunamaz hale getirir. UPDATE deyiminin, önemli veriler içeren bir veritabanında kullanılmadan önce ayrı bir boş veritabanı üzerinde dikkatli bir şekilde test edilmesi önerilir.

  5. Tablo X'daki değişiklik diğer tabloları veya dizinleri de etkiliyorsa veya tetikleyiciler şema içindeki görünümlerse, diğer tablo dizinlerini ve görünümlerini değiştirmek için UPDATE deyimlerini çalıştırın. Örneğin, bir sütunun adı değişirse, bu sütuna başvuran tüm FOREIGN KEY kısıtlamaları, tetikleyicileri, dizinleri ve görünümleri değiştirilmelidir.

    Dikkat: Bir kez daha, sqlite_master tablosunda bu şekilde değişiklik yapılması, değişiklik bir hata içeriyorsa veritabanını bozuk ve okunamaz hale getirecektir. Önemli prosedürler içeren bir veritabanında kullanmadan önce bu prosedürün tamamını ayrı bir test veritabanında dikkatlice test edin ve / veya bu prosedürü çalıştırmadan önce önemli veritabanlarının yedek kopyalarını alın.

  6. Şema sürüm numarasını PRAGMA'yı kullanarak artırın schema_version = X Burada X, yukarıdaki 2. adımda bulunan eski şema sürüm numarasından bir kat daha fazladır.

  7. PRAGMA writable_schema = OFF kullanarak şema düzenlemeyi devre dışı bırakın.

  8. (İsteğe bağlı) Şema değişikliklerinin veritabanına zarar vermediğini doğrulamak için PRAGMA integrity_check komutunu çalıştırın.

  9. Yukarıdaki 1. adımda başlayan işlemi gerçekleştirin.


PRAGMA integrity_check, şemada herhangi bir hata almaz.
Graymatter

ve bununla ilgili sorun nedir?
Mohammad Yahia

1

Bir seçenek, bir çimdik içinde yapılması gerekiyorsa ve ilk sütununuz varsayılan olarak oluşturulduysa, istediğiniz yeni sütunu oluşturmak, içeriği üzerine kopyalamak ve temel olarak eski sütunu "terk" etmektir. mevcut, ancak sadece kullanmıyor / güncellemiyorsunuz vb.)

örn:

alter table TABLE_NAME ADD COLUMN new_column_name TYPE NOT NULL DEFAULT '';
update TABLE_NAME set new_column_name = old_column_name;
update TABLE_NAME set old_column_name = ''; -- abandon old column, basically

Bu, bir sütunun arkasından ayrılır (ve NOT NULL ile oluşturulmuş ancak bir varsayılan olmadan, gelmeyecek ekler başarısız olabilir), ancak sadece bir boş masa ise, ödünleşmeler kabul edilebilir. Aksi takdirde burada belirtilen diğer yanıtlardan birini veya sütunların yeniden adlandırılmasına izin veren farklı bir veritabanı kullanın.



-3

sqlite3 yourdb .dump> /tmp/db.txt
düzenle /tmp/db.txt satır oluştur sütun adını değiştir
sqlite2 yourdb2 </tmp/db.txt
mv / movedb2 yourdb


3
Cevabınız herhangi bir bilgi sağlamaz, bir grup kod / talimat, neden işe yarayacağını veya çalıştırırsanız neyin gerçekleşeceğini düşündüğünüz hakkında fazladan bilgi vermeden tükürür
RGLSV
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.