Tengo dos tablas feed_old (datos predeterminados) y feed_new (datos nuevos) donde el trabajo cron se ejecutará todos los días y actualizará SOLO la tabla feed_new con la información actual
trabajo cron
$url = "localhost/test.xml"; $xml = simplexml_load_file($url); $this->db->query("TRUNCATE TABLE feed_new"); $date = date('Ymd H:i:s'); foreach($xml->Product as $item) { $data = array( 'product_code' => $item->ProductCode, 'name' => $item->Name, 'price' => $item->RetailCurrentPrice, 'stock' => (int)$item->Stock, 'manufacture' => '1', 'date_updated' => $date ); $update_status = $this->model_price->check_price($data); }
Modelo
public function check_price($data) { if($data) { $insert = $this->db->insert('feed_new', $data); return ($insert == true) ? true : false; } }
Desde aqui todo funcionando bien
El problema surge cuando comparo feed_new vs feed_old y obtengo los cambios y muestro todos los registros
Después de comparar feed_new vs feed_old, me gustaría extraer todos los registros de ambas tablas y ordenarlos por niveles.
Nivel 1: si los productos tienen un precio diferente feed_new.price <> feed_old.price
Nivel 2: si el producto de feed_old no existe en feed_new (eso significa que el producto ya no es compatible)
Nivel 3: si el producto de feed_new no existe en feed_old (eso significa que el producto es nuevo)
Nivel 4 - resto de resultados
Consulta de comparación
SELECT fn.name AS name_new, fo.date_updated, fo.id, fo.name,fo.price,fo.product_code, fn.product_code AS product_code_new, fo.stock, fn.price AS price_new, fn.stock AS stock_new, fn.date_updated AS date_updated_new FROM feed_old fo LEFT JOIN feed_new fn ON fo.product_code = fn.product_code UNION ALL SELECT fn.name AS name_new, fo.date_updated, fo.id, fo.name,fo.price,fo.product_code, fn.product_code AS product_code_new, fo.stock, fn.price AS price_new, fn.stock AS stock_new, fn.date_updated AS date_updated_new FROM feed_old fo RIGHT JOIN feed_new fn ON fn.product_code = fo.product_code WHERE fo.product_code IS NULL OR fn.name IS NULL ORDER BY COALESCE(price <> price_new, name_new is NULL, product_code IS NULL) DESC
El problema es que el Nivel - 3 siempre se muestra en el último registro, es decir, después del nivel - 4 en mi ejemplo de trabajo a continuación, puede ver name_new -> test3 está en la parte inferior de la tabla cuando debería estar en la tercera posición.
¿Cómo puedo ordenarlos por niveles superiores?
COALESCE
no parece la función más apropiada para este orden ya que solo devuelve el primer valor que no es NULL
, lo cual no es intuitivo cuando se hacen comparaciones donde los operandos podrían ser NULL
.
Sugeriría usar CASE
en su lugar con un valor entero ficticio para el nivel, algo como esto:
ORDER BY CASE WHEN price_new IS NOT NULL AND price_new <> price THEN 1 WHEN price_new IS NULL THEN 2 WHEN price IS NULL THEN 3 ELSE 4 END
Vea esta demostración de SQLFiddle: http://sqlfiddle.com/#!9/57c8eb3/6 .
Puede escribir una mejor solución usando IFNULL, CASE WHEN y UNION.
Solución: http://sqlfiddle.com/#!9/57c8eb3/21
SELECT fn.name AS name_new, fo.date_updated, fo.id, fo.name,fo.price, fo.product_code, fn.product_code AS product_code_new, fo.stock, fn.price AS price_new, fn.stock AS stock_new, fn.date_updated AS date_updated_new, (case when (IFNULL(fn.product_code,'X') != 'X' and fo.price != fn.price) then 'Level1' when IFNULL(fn.product_code,'X') = 'X' then 'Level2' else 'Level4' end) as Ordering_level FROM feed_old fo LEFT JOIN feed_new fn ON fo.product_code = fn.product_code UNION SELECT fn.name AS name_new, fo.date_updated, fo.id, fo.name,fo.price, fo.product_code, fn.product_code AS product_code_new, fo.stock, fn.price AS price_new, fn.stock AS stock_new, fn.date_updated AS date_updated_new, (case when (IFNULL(fo.product_code,'X') != 'X' and fo.price != fn.price) then 'Level1' when IFNULL(fo.product_code,'X') = 'X' then 'Level3' else 'Level4' end) as Ordering_level FROM feed_old fo RIGHT JOIN feed_new fn ON fn.product_code = fo.product_code order by ordering_level