Bir ya da çok az sorguları birden çok MySQL satır ekran sırasını güncelleniyor

11 Cevap php

Ekran için (1-20) için 20 satır bir sayı ile her söylüyorlar ile ben bir tablo var.

SELECT * FROM `mytable` ORDER BY `display_order` DESC;

Bir yönetici alanında etrafında satırları sürüklemek veya her satır için elle, yeni bir sayı yazın.

Elbette her satır için bir UPDATE sorgusu üzerinde döngü için iyi değil, bir tek alternatif veya daha fazla 20 satır bir hücre güncelleme ya da uygun çok az sorgular, 50-200 + ne?


Edit: iyi tepkiler ve bir çok düşünce. Ben şimdiye kadar kabul ettik fikirleri genişletmek olabilir:

One array string: - örneğin satır 1,9,2,6,23 ben istiyorum sırayla benzersiz satır kimlikleri listeleyen bir dize düzeni olabilir. Sipariş güncellenen, gizli bir alan JavaScript ile güncellemeleri ve veritabanı veya komple bir metin dosyasına ekliyor:

UPDATE `my_dispaly_order_table` SET `display_order`='1,9,2,6,23';

Update each row individually: Bu benim önlemek için ne çalışıyordum ama sadece bu kadar basitçe her satırda GÜNCELLEME çağıran böylece bir vuruşta haftada bir ya da ayda 20-30 çağrılar bir sorun olmayabilir çok seyrek değişmiş olacaktır Ben genelde ne:

UPDATE `mytable` SET `display_order`='1' WHERE `rowId` = 1;
UPDATE `mytable` SET `display_order`='2' WHERE `rowId` = 9;
UPDATE `mytable` SET `display_order`='3' WHERE `rowId` = 2;
UPDATE `mytable` SET `display_order`='4' WHERE `rowId` = 6;
UPDATE `mytable` SET `display_order`='5' WHERE `rowId` = 23;

11 Cevap

Önce aksi mysql kısıtlama sorgusu sırasında kırık olduğunu söyleyecektir, kolon hiçbir UNIQUE indeksine sahip olduğundan emin olmalısınız. : Bundan sonra böyle şeyler yapabilirsiniz

-- Move #10 down (i.e. swap #10 and #11)
UPDATE mytable SET display_order =
  CASE display_order
    WHEN 10 THEN 11
    WHEN 11 THEN 10
  END CASE
WHERE display_order BETWEEN 10 AND 11;

-- Move #4 to #10
UPDATE mytable SET display_order
  CASE display_order
    WHEN 4 THEN 10
    ELSE display_order - 1
  END CASE
WHERE display_order BETWEEN 4 AND 10;

Ama aslında tek adımda şeyler sağlamalıdır. kimlikleri kullanarak değilse, iki adımda takas kırık numaralandırma neden olur. yani:

-- Swap in two steps will not work as demostrated here:

UPDATE mytable SET display_order = 10 WHERE display_order = 11;
-- Now you have two entries with display_order = 10

UPDATE mytable SET display_order = 11 WHERE display_order = 10;
-- Now you have two entries with display_order = 11 (both have been changed)

Ve burada CASE statement of mysql için bir referanstır.

soulmerge cevabı beni düşündürdü ve ben bu daha iyi bir çözüm olduğunu düşünüyorum. Yapmanız gereken () IN kullanan kimliği ile satırları seçin ve ardından değeri ayarlamak için VAKA kullanmaktır.

UPDATE mytable SET display_order =
  CASE id
    WHEN 10 THEN 1
    WHEN 23 THEN 2
    WHEN 4 THEN 3
  END CASE
WHERE id IN (10, 23, 4)

Benim şimdiki uygulaması bunun için bir ihtiyaç var. PHP, jQuery UI yerleşik sıralanabilir özellikten id yılların tefrika (ve sıralı) set alıyorum. Yani dizi bu gibi görünüyor:

$new_order = array(4, 2, 99, 15, 32); // etc

Tek MySQL güncelleştirme sorgusu oluşturmak için, ben bunu:

$query = "UPDATE mytable SET display_order = (CASE id ";
foreach($new_order as $sort => $id) {
  $query .= " WHEN {$id} THEN {$sort}";
}
$query .= " END CASE) WHERE id IN (" . implode(",", $new_order) . ")";

Sonunda "implode" sadece) (IN için bana ID listesini verir. Bu benim için güzel çalışıyor.

Biraz geç, ama başkasına faydalı olabilir:

UPDATE mytable SET display_order = FIND_IN_SET(rowId, '1,9,2,6,23') WHERE rowId in (1,9,2,6,23)

Birkaç tabloların içine sarmak için deneyebilirsiniz, ben tek tek mümkün olduğunu sanmıyorum. Yani, örneğin, diyelim ki 10 satır güncellemek için gidiyoruz diyelim. Sen 10 sonra her kayıt çarptı olmak istiyorum.

UPDATE table SET col=col+1 WHERE col > 10
UPDATE table SET col=10 WHERE id = X
...

Ama gerekli tüm mantık rulo gerçekten zor. Bazı kayıtlar belki bir eksilme, vb gerekir çünkü. Siz vb çoğaltmaları önlemek istiyoruz.

Kazanç vs geliştirici zaman açısından bu düşünün.

Birisi günde bir kez bu sıralar bile, havai Eğer 20 sorguları çalıştırmak kalmamak için bu özelliği bir saklı yordam bunu sabitleme, ya da sözde-optimize karşılaştırıldığında minimal olduğu için. Bu günde 100 kez çalışmazsa, 20 sorgular mükemmel para cezası.

Ben bu sorun hakkında düşünüyorum ve ben geldi çözüm düzeni olarak bir ondalık sayı olan ve bir sonraki ve bir önceki öğe arasındaki bir dizi madde değişikliği sayısını değiştirmek

Order    Item
-----    ----
1        Original Item 1
2        Original Item 2
3        Original Item 3
4        Original Item 4
5        Original Item 5

Eğer 2. pozisyona 4. madde değiştirirseniz, olsun:

Order    Item
-----    ----
1        Original Item 1
1.5      Original Item 4
2        Original Item 2
3        Original Item 3
5        Original Item 5

Eğer 3üncü pozisyona öğeyi 3 değiştirirseniz, olsun:

Order    Item
-----    ----
1        Original Item 1
1.5      Original Item 4
1.75     Original Item 3
2        Original Item 2
5        Original Item 5

Teorik olarak orada iki ondalık arasında bir ondalık her zaman, ama bazı depolama sınırları çarptırılabilir.

Sadece satır güncelleştirmek için bu şekilde yeniden sipariş ediliyor.

Eğer satırları sürüklemek için gerekiyorsa, bu bir linked list için iyi bir uygulama olduğunu.

Eğer (sürece bitişik olduğu gibi) bütün blok hareket bile - sizin satırlar bir linked list Bir seferde 3 satırlar en güncellemek anlamına gelir ile sipariş olması.

Bu gibi satır bir tablo oluşturun:

CREATE TABLE t_list (
        id INT NOT NULL PRIMARY KEY,
        parent INT NOT NULL,
        value VARCHAR(50) NOT NULL,
        /* Don't forget to create an index on PARENT */
        KEY ix_list_parent ON (parent)
)

id   parent  value

1    0       Value1
2    3       Value2
3    4       Value3
4    1       Value4

ve sırayla satırları seçmek için bu MySQL sorguyu kullanabilirsiniz:

SELECT  @r := (
        SELECT  id
        FROM    t_list
        WHERE   parent = @r
        ) AS id
FROM    (
        SELECT  @r := 0
        ) vars,
        t_list

Bu bağlantılı listesinde geçiş ve sipariş öğeleri dönecektir:

id   parent  value

1    0       Value1
4    1       Value4
3    4       Value3
2    3       Value2

Bir satır taşımak için, parent satır, parent bugünkü çocuğun güncellemeniz gerekir, ve parent Eğer 'satırın önce takarak yeniden.

Verimli bunu nasıl benim blog makale bu dizi görmek MySQL:

Her durum için biraz daha farklı ele alınmalıdır satır kilitleme ile bazı sorunlar vardır, çünkü makalelerin çok sayıda bulunmaktadır.

This is a great way of sorting items on a database. Exactly what i was looking for ;)

İşte Jamon Holmgren sürümünün geliştirilmiş bir versiyonu bulunuyor. Bu fonksiyon tamamen dinamiktir:

function reOrderRows($tablename, $ordercol, $idsarray){

    $query = "UPDATE $tablename SET $ordercol = (CASE $ordercol ";
    foreach($idsarray as $prev => $new) {
      $query .= " WHEN $prev THEN $new\n";
    }
    $query .= " END) WHERE $ordercol IN (" . implode(",", array_keys($idsarray)) . ")";

    mysql_query($query);
}

Bu, sadece amaçları siparişi için masaya $tablename üzerine bir sütun $ordercol sahip olduğunu varsayar.

The $idsarray is an array in the format array("current_order_num" => "updated_order_num").

Yani sadece tablodaki iki satır takas etmek istiyorsanız (örneğin olduğunu düşünün bir "yukarı taşımak" ve web sayfanızda simgeleri "aşağı hareket") Eğer bir öncekinin üstüne bu fonksiyonu kullanabilirsiniz:

function swapRows($tablename, $ordercol, $firstid, $secondid){
    $swaparray = array("$firstid" => "$secondid", "$secondid" => "$firstid");
    reOrderRows($tablename, $ordercol, $swaparray); 
}

Eğer tek seferde tablosunu güncellemek için UPDATE çoklu masa sürümünü kullanın sonra, geçici bir tablo oluşturmak ve değiştirmek istediğiniz satır birincil anahtar ve bu satırlar için display_order yeni değerleri ile doldurmak olabilir. Ben hem yaklaşımları test etmeden, ancak bu hızlı olduğunu kabul etmem.

Tabloya bir id (veya başka bir tuşa) ekleyin ve güncelleme nerede değiştirilen satır id (veya anahtar) = id (veya anahtar).

Tabii ki, emin herhangi bir sırayla görüntüleniyor display_order içinde bağları iyisin, ya da bir saniye tanıtacağız hiçbir yinelenen display_order değerleri vardır ya o ya o yapmak zorunda olacak, liste sırasına tie-kesici .

Bir yeniden takın tüm satırları silmek olabilir - (Tüm verileri seçmek için gerekiyorsa ya da üç) sadece iki sorgularda tüm operasyonu yapardı. Ben daha hızlı olmayı saymak olmaz, ve bir işlem içinde bunu yapmak lazım ya da çok uzun zaman önce yedekleme için başlığı olacak. Ayrıca masa parçalanmasına yol açabilir.

Daha iyi bir seçenek, bir tarih olarak her bir değişikliği kaydetmek için olabilir o zaman böyle bir şey yapın:

Örnek, pozisyon 10 12 için iki aşağı taşınır

UPDATE table SET display_order = display_order -1 WHERE display_order BETWEEN 10 AND 12
UPDATE table SET display_order = 12 WHERE row_id = [id of what was row 10]

Geçici bir değişken olarak yeni sipariş toplamak ve yönetici alanı için bir "bu emri kaydetmek" düğmesine koydu. Sonra bir tur ile satırlar için sırasını kaydetmek.

(DBMS, mümkün olması için kullanılan hemen hemen hiçbir güncellemeleri, düşük seviyede fakat bütün satırın yeni bir örneğini kaydetmek ve eski silmek için) daha iyi yanıt süreleri, geri alınamaz değişiklikler, daha az modifiye satır alırsınız.

Sonuçta, bir bütün tekrar düzenlenmesi için düşük maliyetli bir çözüm olacaktır ve güncelleme optimizasyonu bazı kodlama tasarruf sağlayacaktır.