SQL: bir kerede 1000 satır güncellemek için bir CASE deyimi kullanma

2 Cevap php

Tamam, bu bir CASE STATEMENT kullanmak istiyorum, ama bu birlikte kaybettim. Temelde, ama sadece "pozisyon" sütununda, satır bir ton güncellemeniz gerekir. Bir id_layout ve id_layout_position bazında position - 1 kaldırıldı konum değerinin daha büyük UPDATE, tüm konum değerleri gerekmektedir.

OK, here is a pic of what the table looks like: alt text

Şimdi ben daire içine satırı silin diyelim, bu = 2 pozisyonu kaldırmak ve beni verecektir:. 0, 1, 3, 5, 6, 7, ve 4 görünüyor böylece, 2'den büyük olan pozisyon değerleri yeniden konumlandırmak gerekir bu şekilde: 0, 1, 2, 4, 5, 6, ve 3.

Tamam, İşte SATIR silerek içinde bugüne kadar ne var, işte bu (NOT arar nasıl: $ module_info ['klon'] Yukarıdaki tabloda silmek için klonların bir dizi = hiçbiri olmazdı çünkü Tüm id_clone değerler 0 ve $ module_info ['id'] biz) çıkarıyorsanız id_module değerdir:

// Get rid of id_clone = 0, because we can't use them.
$module_info['clones'] = array_values(array_filter($module_info['clones']));

// Selecting the positions.
if (isset($module_info['clones'][0]))
    $query = 'id_module = {int:id_module} || id_clone IN ({array_int:id_clones})';
else
    $query = 'id_module = {int:id_module}';

$request = $smcFunc['db_query']('', '
    SELECT
        id_position, id_layout_position, id_layout, position
    FROM {db_prefix}dp_module_positions
    WHERE ' . $query,
    array(
        'zero' => 0,
        'id_module' => $module_info['id'],
        'id_clones' => $module_info['clones'],          
    )
);

while ($row = $smcFunc['db_fetch_assoc']($request))
{
    $module_info['position'][$row['id_layout']]['pos' . $row['id_position'] . $row['position'] . '_' . $row['id_layout_position']] = $row['position'];
    $module_info['id_positions'][] = $row['id_position'];
}

$smcFunc['db_free_result']($request);

// Remove all module and clone positions from the layout!
$smcFunc['db_query']('', '
    DELETE FROM {db_prefix}dp_module_positions
    WHERE id_position IN ({array_int:id_positions})',
    array(
        'id_positions' => $module_info['id_positions'],
    )
);

foreach($module_info['position'] as $id_layout => $id_layout_pos)
{
    foreach($id_layout_pos as $key => $position_val)
    {
        $lPos = explode('_', $key);
        $lPosId = (int) $lPos[1];

        $smcFunc['db_query']('', '
            UPDATE {db_prefix}dp_module_positions
            SET
                position = position - 1
            WHERE position > {int:position} AND id_layout = {int:id_layout} AND id_layout_position = {int:id_layout_position}',
            array(
                'id_layout' => (int) $id_layout,
                'position' => (int) $position_val,
                'id_layout_position' => $lPosId,
            )
        );
    }
}

NEW QUESTION: THERE's Just gotta be some sort of way to use a CASE STATEMENT in this UPDATE now. For Example, I now need to update all positions to position - 1, on a per id_layout, and per id_layout_position basis. BUT only where the position is greater than the current position for that id_layout and id_layout_position value.

Bir FOREACH LOOP kullanmadan bunu yapmak için yine de var mı?

2 Cevap

Bir satırı silmeden önce, bu pozisyon almak ve daha yüksek bir konuma sahip tüm satırların konumunu azaltma olabilir.

Sahte kod:

function deleteRow($id){
  DB::startTransaction()
  try{
    $infos = DB::getData('SELECT position FROM db_positions WHERE id_position = :ID', array(':ID' => $id));
    if(empty($infos)){
      throw("useless ID");
    }
    DB::query('DELETE FROM db_positions WHERE id_position = :ID', array(':ID' => $id));
    DB::query('UPDATE db_positions SET position = position - 1 WHERE position > :position', array(':position' => $infos['position']);
    DB::commit();
  }
  catch(Exception $e){
    DB::rollBack();
  }
}

Kesintisiz dizisi ile güncellemek için aşağıdaki kullanabilirsiniz:

SET @reset := 0; 
UPDATE dp_positions
SET
  positions = 
  CASE          
    WHEN id_layout_position > @reset THEN 
      IF(@pos:=0,NULL, @reset:=id_layout_position)        
    ELSE @pos := @pos + 1    
  END - 1  
ORDER BY id_layout_position, position;

Notes: @reset should be set to minimum value of id_layout_position, assuming that you are restarting the counter on id_layout_position change, if it is more complicated the WHEN condition will need to change and you might need more variables to hold the values from previous row.
Furthermore the IF is a hack, it will never be NULL as long you are setting @pos to 0 and not to some other starting value, I just didn't know how to force mysql to evaluate two expressions (anyone, is there something elegant there?)

Yukarıdaki test edilmiş, ancak farklı sütun / tablo adları (olası hataları yeniden yazmak) ile almaktadır.

EDIT: Benim test üzerinde bir hata var, ve ayrıca OP, bu yüzden burada bir çerçeve güvenlik atlamak için bir düzeltme ve saklı yordam sürümü bulunuyor ihtiyacı görünüyor, çok iyi değildi

phpmyadmin veya mysql komut satırı yürütmek kullanma

delimiter //
CREATE PROCEDURE `renumerate`()
BEGIN
SET @pos := -1;
SET @reset := (SELECT MIN(id_layout_position) FROM dp_position);
UPDATE
  dp_positions
SET
  position = 
    CASE          
      WHEN b > @reset THEN 
        IF(@reset:=id_layout_position, @pos:=0, @pos:=0)        
      ELSE @pos := @pos + 1    
    END
ORDER BY id_layout_position, position;
END //
delimiter ;

(in case you use phpMyAdmin do not use delimiter statements but directly specify delimiter in the interface as //). When calling the procedure execute normal SQL

$smcFunc['db_query']('', 'CALL renumerate()');

Benim test bu sefer daha iyi olduğunu umuyoruz.