2009-05-27 9 views
0

je dois effectuer une requête comme ceci:Sql syntaxe de requête Server

SELECT *, 
    (SELECT Table1.Column 
    FROM Table1 
    INNER JOIN Table2 ON Table1.Table2Id = Table2.Id 
    ) as tmp 
FROM Table2 WHERE tmp = 1 

Je sais que je peux prendre une solution mais je voudrais savoir si cette syntaxe est possible car il est (je pense) Mysql .

+0

Pourquoi un gourou du serveur SQL sait-il si cette syntaxe fonctionne dans MySQL? Ce sont deux systèmes de bases de données complètement différents. –

+0

Il veut savoir si une requête sqlserver a un équivalent dans mysql. La meilleure personne à demander serait quelqu'un qui a utilisé les deux. Je doute que tout cela soit inhabituel - j'ai utilisé les deux. Malheureusement, je n'ai pas d'instance mysql sous mon contrôle, donc je me sentirais mal à l'aise de soumettre une réponse sans la vérifier sur une table de test. De toute façon, je ne pense pas que ce soit votre place pour poser cette question, surtout quand il est clair de sa question qu'il a besoin d'une version mysql d'une requête sqlserver. –

+0

Sûr semble qu'il veut une version SQL Server d'un querry MySQL ... – CSharpAtl

Répondre

0

Vous avez déjà une variété de réponses, certaines d'entre elles plus utiles que d'autres. Mais pour répondre directement à votre question:

Non, SQL Server ne vous permettra pas de référencer l'alias de colonne (défini dans la liste de sélection) dans le prédicat (la clause WHERE). Je pense que cela suffit pour répondre à la question que vous avez posée.

Détails supplémentaires:

(cette discussion va au-delà de la question initiale que vous avez demandé.)

Comme vous l'avez dit, il y a plusieurs solutions de contournement disponibles. Le plus problématique avec la requête que vous avez publiée (comme d'autres l'ont déjà signalé) est que nous ne sommes pas sûrs que la sous-requête de la liste SELECT ne renvoie qu'une seule ligne. Si elle ne retourne plus d'une ligne, SQL Server lancera une « trop de lignes » exception:

 
    Subquery returned more than 1 value. 
    This is not permitted when the subquery 
    follows =, !=, , >= or when the 
    subquery is used as an expression. 

Pour la discussion qui suit, je vais supposer que cette question est déjà suffisamment pris en compte.

Parfois, la façon la plus simple de rendre l'alias disponible dans le prédicat consiste à utiliser une vue en ligne.

SELECT v.* 
    FROM (SELECT * 
       , (SELECT Table1.Column 
        FROM Table1 
        JOIN Table2 ON Table1.Table2Id = Table2.Id 
        WHERE Table1.Column = 1 
       ) as tmp 
      FROM Table2 
     ) v 
WHERE v.tmp = 1 

Notez que SQL Server ne poussera pas le prédicat de la requête externe (WHERE v.tmp = 1) dans la sous-requête dans la vue en ligne. Vous devez donc le faire vous-même en incluant le prédicat WHERE Table1.Column = 1 dans la sous-requête, en particulier si vous dépendez de cela pour que la sous-requête renvoie une seule valeur.

C'est juste une approche pour contourner le problème, il y en a d'autres. Je soupçonne que le plan de requête pour cette requête SQL Server ne va pas être optimal, pour la performance, vous voulez probablement aller avec un prédicat JOIN ou un prédicat EXISTS.

REMARQUE: je ne suis pas un expert en matière d'utilisation de MySQL. Je ne suis pas très familier avec le support de MySQL pour les sous-requêtes. Je sais (d'après une expérience douloureuse) que les sous-requêtes n'étaient pas supportées dans MySQL 3.23, ce qui rendait particulièrement pénible la migration d'une application d'Oracle 8 vers MySQL 3.23.

Oh et btw ... aucun intérêt à personne en particulier, le moteur SGBD Teradata NE ont une extension qui permet le mot-clé NOMMÉ à la place du mot-clé AS, et une expression nommée CAN être référencé ailleurs dans la requête, y compris la clause WHERE, la clause GROUP BY et la clause ORDER BY. Shuh-weeeet

2
SELECT * 
FROM (
     SELECT t.*, 
       (
       SELECT Table1.Column 
       FROM Table1 
       INNER JOIN 
         Table2 
       ON  Table1.Table2Id = Table2.Id 
       ) as tmp 
     FROM Table2 t 
     ) q 
WHERE tmp = 1 

Cette syntaxe est valide, mais il échouera (à la fois dans MySQL et SQL Server) si la sous-requête renvoie plus de 1 ligne

Qu'est-ce que vous essayez de faire exactement?

Veuillez fournir quelques exemples de données et le résultat souhaité.

+0

Au moins cette réponse ne suppose pas qu'il * voulait vraiment * sélectionner une valeur de colonne. –

8

La requête que vous avez publiée ne fonctionnera pas sur le serveur SQL, car la sous-requête de votre clause select peut renvoyer plusieurs lignes. Je ne sais pas comment MySQL le traitera, mais d'après ce que je lis, MySQL produira aussi une erreur si la sous-requête renvoie des doublons. Je sais que SQL Server ne le compilera même pas. La différence est que MySQL va au moins tenter d'exécuter la requête et si vous êtes très chanceux (Table2Id est unique dans Table1), il réussira. Plus probablement va retourner une erreur. SQL Server n'essaiera pas de l'exécuter du tout.

Voici une requête qui devrait s'exécuter sur l'un ou l'autre système, et ne provoquera pas d'erreur si Table2Id n'est pas unique dans Table1. Il va retour lignes « en double » dans ce cas, où la seule différence est la source de la valeur Table1.Column:

SELECT Table2.*, Table1.Column AS tmp 
FROM Table1 
INNER JOIN Table2 ON Table1.Table2Id = Table2.Id 
WHERE Table1.Column = 1 

Peut-être que si vous partagiez ce que vous essayez d'accomplir, nous pouvons vous aider à rédiger votre requête qui le fait.

+0

mes pensées exactement ... – gbn

+0

J'utilise souvent des jointures à gauche au lieu de jointures internes. La jointure à gauche en garantira une, et une seule occurrence d'une rangée de données dans une table qui m'intéresse. Cela dit, je pense que Table2 est la table qui vous intéresse, et devrait être listée en premier: 'FROM Table2 LEFT JOIN Table1 ...' – Kieveli

+1

Ce site est * cassé * si des réponses incorrectes comme celle-ci sont votées. –

0

Ce type de syntaxe est fondamentalement valide (vous devez déplacer le where tmp=... sur externe "select * from (....)", cependant), bien qu'il soit ambigu puisque vous avez deux ensembles nommés "Table2" - vous devrait probablement définir des alias sur au moins un de vos usages de cette table pour éclaircir l'ambiguïté.

Sauf si vous vouliez renvoyer une colonne de la table 1 correspondant aux colonnes de la table 2 ... auquel cas vous auriez peut-être simplement voulu rejoindre les tables?

+0

Il n'est pas permis (dans SQL Server 2005) de référencer un alias pour une expression dans la liste SELECT du prédicat de requête. – spencer7593

+0

bon point, et en fait c'est vrai dans tous les DB que j'ai utilisés autant que je me souvienne. – araqnid

2

Je suis d'accord avec la solution de Joel, mais je veux discuter de la raison pour laquelle votre requête serait une mauvaise idée à utiliser (même si la syntaxe est essentiellement valide). C'est une sous-requête corrélée. Le premier problème avec ceux-ci est qu'ils ne fonctionnent pas si la sous-requête peut éventuellement renvoyer plus d'une valeur pour un enregistrement. Le deuxième problème, plus critique (dans mon esprit), est qu'ils doivent fonctionner rangée par rangée plutôt que sur l'ensemble des données. Cela signifie qu'ils affecteront presque toujours les performances. Les sous-requêtes corrélées ne devraient donc presque jamais être utilisées dans un système de production. Dans ce cas simple, la jointure Joel a montré est la bonne solution.

Si la sous-requête est plus compliquée, vous pouvez la transformer en une table dérivée (cela corrige également les plusieurs valeurs associées à un problème d'enregistrement). Alors qu'une table dérivée ressemble beaucoup à une sous-requête corrélée pour les non-initiés, elle ne fonctionne pas de la même manière car elle agit sur l'ensemble des données plutôt que sur la rangée par rangée et sera donc souvent beaucoup plus rapide. Vous faites essentiellement la requête une table dans la jointure. Voici un exemple de réécriture de votre requête sous la forme d'une table dérivée:

(Bien sûr, dans le code de production vous pas utiliser select * soit en particulier dans une jointure, préciser les champs dont vous avez besoin)

SELECT *  
FROM Table2 t2 
JOIN 
(SELECT Table1.[Column], Table1.Table2Id as tmp  
FROM Table1  
INNER JOIN Table2 ON Table1.Table2Id = Table2.Id ) as t 
ON t.Table2Id = Table2.Id 
WHERE tmp = 1 
+0

+1 Bons points, mais FWIW, MySQL n'utilise pas les crochets pour les identifiants délimités. C'est une convention Microsoft/Sybase. Dans MySQL, utilisez les guillemets par défaut ou définissez SQL_MODE sur ANSI_QUOTES et utilisez des guillemets doubles. –

+0

Je me suis dit qu'il n'avait pas vraiment une colonne nommée colonne, mais je ne savais pas que mysql ne permettait pas les parenthèses. Je viens de mettre les crochets pour tester ma syntaxe. Merci pour l'info, ne sait jamais quand je pourrais un jour besoin de savoir mysql. – HLGEM