sql >> Databáze >  >> RDS >> Mysql

Pořadí dotazů MySQL podle většiny vyplněných polí

Pokud vím, MySQL nemá žádnou funkci pro počítání nenulových polí na řádku.

Takže jediný způsob, který mě napadá, je použít explicitní podmínku:

SELECT * FROM mytable
    ORDER BY (IF( column1 IS NULL, 0, 1)
             +IF( column2 IS NULL, 0, 1)
             ...
             +IF( column45 IS NULL, 0, 1)) DESC;

...je to ošklivé jako hřích, ale mělo by to stačit.

Můžete také navrhnout TRIGGER pro zvýšení dalšího sloupce "fields_filled". Spouštěč vás stojí UPDATE , 45 IF vás bolí na SELECT; budete muset modelovat, co je pohodlnější.

Všimněte si, že indexování všech polí urychlí SELECT vás bude při aktualizaci stát (a 45 různých indexů pravděpodobně stojí tolik jako skenování tabulky na select, neříkám, že indexované pole je VARCHAR ). Proveďte nějaké testy, ale věřím, že řešení 45-IF bude pravděpodobně celkově nejlepší.

AKTUALIZACE :Pokud můžete přepracovat strukturu tabulky, abyste ji trochu normalizovali, můžete pole vložit do my_values stůl. Pak byste měli "tabulku záhlaví" (možná pouze s jedinečným ID) a "tabulku dat". Prázdná pole by vůbec neexistovala a pak byste je mohli seřadit podle počtu vyplněných polí pomocí RIGHT JOIN , počítaje vyplněná pole pomocí COUNT() . To by také výrazně urychlilo UPDATE operací a umožní vám efektivně využívat indexy.

PŘÍKLAD (od nastavení tabulky po nastavení dvou normalizovaných tabulek) :

Řekněme, že máme sadu Customer evidence. Budeme mít krátkou podmnožinu „povinných“ údajů, jako je ID, uživatelské jméno, heslo, e-mail atd.; pak budeme mít možná mnohem větší podmnožinu „nepovinných“ údajů, jako je přezdívka, avatar, datum narození a tak dále. Jako první krok předpokládejme, že všechna tato data jsou varchar (toto na první pohled vypadá jako omezení ve srovnání s řešením s jednou tabulkou, kde každý sloupec může mít svůj vlastní datový typ).

Takže máme tabulku jako,

ID   username    ....
1    jdoe        etc.
2    jqaverage   etc.
3    jkilroy     etc.

Pak máme tabulku nepovinných dat. Zde John Doe vyplnil všechna pole, Joe Q. Průměrně jen dvě a Kilroy žádné (i když byl zde).

userid  var   val
1       name  John
1       born  Stratford-upon-Avon
1       when  11-07-1974
2       name  Joe Quentin
2       when  09-04-1962

Abychom mohli reprodukovat výstup "single table" v MySQL, musíme vytvořit poměrně složitý VIEW se spoustou LEFT JOIN s. Toto zobrazení bude nicméně velmi rychlé, pokud budeme mít index založený na (userid, var) (ještě lepší, když použijeme číselnou konstantu nebo SET místo varchar pro datový typ var :

CREATE OR REPLACE VIEW usertable AS SELECT users.*,
    names.val AS name // (1)
FROM users
    LEFT JOIN userdata AS names ON ( users.id = names.id AND names.var = 'name') // (2)
;

Každé pole v našem logickém modelu, např. „name“, bude obsaženo v n-tici ( id, 'name', value ) ve volitelné datové tabulce.

A získá řádek ve tvaru <FIELDNAME>s.val AS <FIELDNAME> v sekci (1) výše uvedeného dotazu s odkazem na řádek ve tvaru LEFT JOIN userdata AS <FIELDNAME>s ON ( users.id = <FIELDNAME>s.id AND <FIELDNAME>s.var = '<FIELDNAME>') v sekci (2). Dotaz tedy můžeme sestavit dynamicky zřetězením prvního textového řádku výše uvedeného dotazu s dynamickou sekcí 1, textem 'FROM users' a dynamicky vytvořenou sekcí 2.

Jakmile to uděláme, SELECTy v pohledu jsou přesně identické jako dříve – ale nyní načítají data ze dvou normalizovaných tabulek prostřednictvím JOINů.

EXPLAIN SELECT * FROM usertable;

nám řekne, že přidání sloupců do tohoto nastavení znatelně nezpomalí operace, tj. toto řešení se poměrně dobře škáluje.

Bude nutné upravit VLOŽENÍ (vkládáme pouze povinné údaje, a to pouze v první tabulce) a také AKTUALIZACE:AKTUALIZUJEME buď tabulku povinných údajů, nebo jeden řádek tabulky nepovinných údajů. Ale pokud tam cílový řádek není, musí být INSERTed.

Musíme tedy vyměnit

UPDATE usertable SET name = 'John Doe', born = 'New York' WHERE id = 1;

s 'upsert', v tomto případě

INSERT INTO userdata VALUES
        ( 1, 'name', 'John Doe' ),
        ( 1, 'born', 'New York' )
    ON DUPLICATE KEY UPDATE val = VALUES(val);

(Potřebujeme UNIQUE INDEX on userdata(id, var) pro ON DUPLICATE KEY do práce).

V závislosti na velikosti řádku a problémech s diskem může tato změna přinést znatelné zvýšení výkonu.

Všimněte si, že pokud tato úprava neprovedete, stávající dotazy nevyvolají chyby – v tichosti selžou .

Zde například upravíme jména dvou uživatelů; jeden má v záznamu jméno, druhý má NULL. První je upraven, druhý nikoli.

mysql> SELECT * FROM usertable;
+------+-----------+-------------+------+------+
| id   | username  | name        | born | age  |
+------+-----------+-------------+------+------+
|    1 | jdoe      | John Doe    | NULL | NULL |
|    2 | jqaverage | NULL        | NULL | NULL |
|    3 | jtkilroy  | NULL        | NULL | NULL |
+------+-----------+-------------+------+------+
3 rows in set (0.00 sec)
mysql> UPDATE usertable SET name = 'John Doe II' WHERE username = 'jdoe';
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0
mysql> UPDATE usertable SET name = 'James T. Kilroy' WHERE username = 'jtkilroy';
Query OK, 0 rows affected (0.00 sec)
Rows matched: 0  Changed: 0  Warnings: 0
mysql> select * from usertable;
+------+-----------+-------------+------+------+
| id   | username  | name        | born | age  |
+------+-----------+-------------+------+------+
|    1 | jdoe      | John Doe II | NULL | NULL |
|    2 | jqaverage | NULL        | NULL | NULL |
|    3 | jtkilroy  | NULL        | NULL | NULL |
+------+-----------+-------------+------+------+
3 rows in set (0.00 sec)

Abychom zjistili hodnocení každého řádku, u uživatelů, kteří mají hodnocení, jednoduše načteme počet řádků uživatelských dat na ID:

SELECT id, COUNT(*) AS rank FROM userdata GROUP BY id

Nyní, abychom extrahovali řádky v pořadí „vyplněný stav“, děláme:

SELECT usertable.* FROM usertable
    LEFT JOIN ( SELECT id, COUNT(*) AS rank FROM userdata GROUP BY id ) AS ranking
ON (usertable.id = ranking.id)
ORDER BY rank DESC, id;

LEFT JOIN zajišťuje, že jsou načteni i bezúhonní jedinci a další řazení podle id zajišťuje, že lidé se stejnou hodností vždy vyjdou ve stejném pořadí.




  1. Otázky/návrhy na vzor třídy PHP databáze

  2. 10 Klávesové zkratky navigačního panelu Microsoft Access

  3. SQL Datatype, který se má použít při vkládání peněz

  4. Sqlite 3 Insert and Replace selže ve více než 1 jedinečném sloupci