1
votes

MySQL - Trouver la première correspondance ou le caractère générique

J'ai une table avec des variables / colonnes mappées, par exemple:

SELECT * 
FROM test 
WHERE ele = '123' (dim1 = 'DM1' OR dim1 = '*') 
  AND (dim2 = 'DM2' OR dim2 = '*') 
  AND (dim3 = 'DM3' OR dim3 = '*');

Je veux trouver la première correspondance avec n'importe quelle colonne qui pourrait renvoyer la correspondance requise à partir de la colonne ou du caractère générique à la place.

+------+------+------+------+
| ele  | dim1 | dim2 | dim3 |
+------+------+------+------+
| 123  | *    | *    | *    |
| 123  | DM1  | *    | *    |
| abc  | *    | DM2  | *    |
+------+------+------+------+

CREATE TABLE `test` 
(
    `ele` varchar(36) NOT NULL,
    `dim1` varchar(36) NOT NULL,
    `dim2` varchar(36) NOT NULL,
    `dim3` varchar(36) NOT NULL,
    UNIQUE KEY `test_dim1_dim2_dim3_uindex` (`ele`, `dim1`,`dim2`,`dim3`)
);

Il se produit que cela renvoie les deux colonnes (trouvé un et le caractère générique correspondant, bien sûr).

Existe-t-il un moyen de trouver une correspondance ou un caractère générique en cas d'échec? p >


4 commentaires

Vous avez d'abord besoin d'un membre de commande pour définir le premier et le suivant. Ensuite, ORDER BY order_member LIMIT1 peut vous aider.


Ce type de problème est symptomatique d'une mauvaise conception. Pouvez-vous modifier votre schéma?


@ Fraise ouais, je peux le modifier. Toute suggestion?


L'une de ces réponses a-t-elle résolu votre problème? Sinon, pourriez-vous fournir plus d'informations pour y répondre? Sinon, pensez à marquer la réponse qui a le mieux résolu votre problème. Voir stackoverflow.com/help/someone-answers


3 Réponses :


-1
votes

Faites-le comme deux requêtes distinctes, que vous combinez avec UNION . Donnez-leur à chacun une colonne de classement et utilisez-la pour préférer la correspondance réelle au lieu du caractère générique.

SELECT *
FROM (
    SELECT 1 AS o, test.*
    FROM test
    WHERE dim1 = 'DM1' OR dim2 = 'DM2' OR dim3 = 'DM3'
    LIMIT 1
    UNION
    SELECT 2 AS o, test.*
    FROM test
    WHERE dim1 = '*' AND dim2 = '*' AND dim3 = '*'
    LIMIT 1
) AS x
ORDER BY o
LIMIT 1


2 commentaires

Cela effectue une recherche complète dans 3 requêtes dérivées. Cela ne semble pas être le moyen le plus performant, mais merci quand même.


Vous pouvez mettre LIMIT 1 dans les sous-requêtes pour que l'union finale soit minuscule. Il devrait probablement y avoir un ordre dans les sous-requêtes également, mais il n'y a rien dans votre question initiale qui suggère comment classer les deux types de résultats.



0
votes

Pas une réponse; trop long pour un commentaire ...

Un environnement normalisé pourrait ressembler davantage à ceci:

entity dim val
     1   1   *
     1   2   *
     1   3   *
     2   1   DM1
     2   2   *
     2   3   *


1 commentaires

Quoi de neuf dans cet environnement? J'utilise DM1 , DM2 comme exemple, mais la colonne a en fait des valeurs UUID et UNIQUE INDEX sur les combinaisons également . Quoi qu'il en soit, la question a été modifiée pour être claire.



1
votes

Une façon de faire serait de compter le nombre de correspondances génériques pour chaque ligne (en tirant parti du fait que dans un contexte numérique MySQL traite un booléen comme 1 ou 0), puis triez par ce nombre croissant, a LIMIT 1 pour renvoyer uniquement la ligne avec le moins de correspondances génériques, par exemple

ele     dim1    dim2    dim3
123     DM1     *       *

Sortie:

SELECT *
FROM test
WHERE ele = 123 AND
      (dim1 = 'DM1' OR dim1 = '*') AND
      (dim2 = 'DM2' OR dim2 = '*') AND
      (dim3 = 'DM3' OR dim3 = '*')
ORDER BY (dim1 = '*') + (dim2 = '*') + (dim3 = '*') ASC
LIMIT 1

Démo sur dbfiddle


1 commentaires

@fiskolin J'ai modifié ma réponse en fonction des modifications que vous avez apportées à votre question. Avez-vous besoin d'autre chose?