J'ai une table appelée map_tags
:
map_id | map_license | map_desc
Et une autre table (widgets
) dont les enregistrements contiennent une référence de clé étrangère (1 à 1) à un enregistrement map_tags
:
widget_id | map_id | widget_name
Etant donné la contrainte que tous les map_license
s sont uniques (cependant, ils ne sont pas configurés en tant que clés sur map_tags
), alors si j'ai un map_license
et un widget_name
, j'aimerais effectuer une insertion sur widgets
tout à l'intérieur de la même instruction SQL:
INSERT INTO
widgets w
(
map_id,
widget_name
)
VALUES (
(
SELECT
mt.map_id
FROM
map_tags mt
WHERE
// This should work and return a single record because map_license is unique
mt.map_license = '12345'
),
'Bupo'
)
Je crois je suis sur la bonne voie, mais je sais d’emblée que c’est un code SQL incorrect pour Postgres. Est-ce que quelqu'un sait la bonne façon de réaliser une telle requête?
INSERT INTO widgets
(
map_id,
widget_name
)
SELECT
mt.map_id, 'Bupo'
FROM
map_tags mt
WHERE
mt.map_license = '12345'
Utilisez la variante INSERT INTO SELECT
, en incluant les constantes dans l’instruction SELECT
.
La syntaxe PostgreSQL INSERT
est la suivante:
INSERT INTO table [ ( column [, ...] ) ]
{ DEFAULT VALUES | VALUES ( { expression | DEFAULT } [, ...] ) [, ...] | query }
[ RETURNING * | output_expression [ [ AS ] output_name ] [, ...] ]
Prenez note de l’option query à la fin de la deuxième ligne ci-dessus.
Voici un exemple pour vous.
INSERT INTO
widgets
(
map_id,
widget_name
)
SELECT
mt.map_id,
'Bupo'
FROM
map_tags mt
WHERE
mt.map_license = '12345'
Réponse rapide: Vous n'avez pas " un seul enregistrement " vous avez un " défini avec 1 enregistrement " Si cela était javascript: Vous avez un "tableau avec 1 valeur" et non "1 valeur".
Dans votre exemple , un enregistrement peut être renvoyé dans la sous-requête, , Mais vous essayez toujours de décompresser un "tableau" d'enregistrements dans des paramètres réels Distincts dans un place qui prend seulement 1 paramètre.
Il m'a fallu quelques heures pour comprendre le "pourquoi pas". Alors que j'essayais de faire quelque chose de très similaire:
Voici mes notes:
tb_table01: (no records)
+---+---+---+
| a | b | c | << column names
+---+---+---+
tb_table02:
+---+---+---+
| a | b | c | << column names
+---+---+---+
|'d'|'d'|'d'| << record #1
+---+---+---+
|'e'|'e'|'e'| << record #2
+---+---+---+
|'f'|'f'|'f'| << record #3
+---+---+---+
--This statement will fail:
INSERT into tb_table01
( a, b, c )
VALUES
( 'record_1.a', 'record_1.b', 'record_1.c' ),
( 'record_2.a', 'record_2.b', 'record_2.c' ),
-- This sub query has multiple
-- rows returned. And they are NOT
-- automatically unpacked like in
-- javascript were you can send an
-- array to a variadic function.
(
SELECT a,b,c from tb_table02
)
;
Fondamentalement, ne fait pas pense à "VALEURS" comme une fonction variadic Qui peut décompresser un tableau d'enregistrements. Aucun argument n’a été décompressé ici comme dans une fonction javascript . Tel que:
function takeValues( ...values ){
values.forEach((v)=>{ console.log( v ) });
};
var records = [ [1,2,3],[4,5,6],[7,8,9] ];
takeValues( records );
//:RESULT:
//: console.log #1 : [1,2,3]
//: console.log #2 : [4,5,7]
//: console.log #3 : [7,8,9]
Retour à votre question SQL:
La réalité de cette fonctionnalité inexistante ne change pas Simplement parce que votre sous-sélection ne contient qu'un seul résultat. C'est A " défini avec un enregistrement " pas " un seul enregistrement ".