PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Comment puis-je insérer des données communes dans une table temporaire à partir de schémas disparates ?

Tout d'abord, vous pouvez créer une VIEW pour fournir cette fonctionnalité :

CREATE VIEW orders AS
SELECT '1'::int            AS source -- or any other tag to identify source
      ,"OrderNumber"::text AS order_nr
      ,"InvoiceNumber"     AS tansaction_id -- no cast .. is int already
      ,"OrderDate" AT TIME ZONE 'UTC' AS purchase_date -- !! see explanation
FROM   tbl_newegg

UNION  ALL  -- not UNION!
SELECT 2
       "amazonOrderId"
      ,"merchant-order-id"
      ,"purchase-date"
FROM   tbl_amazon;

Vous pouvez interroger cette vue comme n'importe quelle autre table :

SELECT * FROM orders WHERE order_nr = 123 AND source = 2;
  • Le source est nécessaire si le order_nr n'est pas unique. Sinon, comment garantiriez-vous des numéros de commande uniques sur différentes sources ?

  • Un timestamp without time zone est une ambiguïté dans un contexte global. Elle n'est bonne qu'en rapport avec son fuseau horaire. Si vous mélangez timestamp et timestamptz , vous devez placer le timestamp à un certain fuseau horaire avec le AT TIME ZONE construire pour que cela fonctionne. Pour plus d'explications, lisez cette réponse connexe .

    J'utilise UTC comme fuseau horaire, vous voudrez peut-être en fournir un autre. Un simple cast "OrderDate"::timestamptz assumerait votre fuseau horaire actuel. AT TIME ZONE appliqué à un timestamp résultats en timestamptz . C'est pourquoi je n'ai pas ajouté d'autre distribution.

  • Pendant que vous pouvez , je conseille de ne pas utiliser d'identificateurs en casse de chameau dans PostgreSQL jamais . Évite de nombreux types de confusion possible. Notez les identifiants en minuscules (sans les guillemets désormais inutiles) que j'ai fournis.

  • N'utilisez pas varchar(25) comme type pour le order_nr . Utilisez simplement text sans modificateur de longueur arbitraire s'il doit s'agir d'une chaîne. Si tous les numéros de commande sont composés exclusivement de chiffres, integer ou bigint serait plus rapide.

Performances

Une façon de rendre cela rapide serait de matérialiser la vue. C'est-à-dire, écrivez le résultat dans une table (temporaire) :

CREATE TEMP TABLE tmp_orders AS
SELECT * FROM orders;

ANALYZE tmp_orders; -- temp tables are not auto-analyzed!

ALTER TABLE tmp_orders
ADD constraint orders_pk PRIMARY KEY (order_nr, source);

Vous avez besoin Un index. Dans mon exemple, la contrainte de clé primaire fournit l'index automatiquement.

Si vos tables sont volumineuses, assurez-vous d'avoir suffisamment de tampons temporaires pour gérer cela dans la RAM avant vous créez la table temporaire. Sinon, cela vous ralentira.

SET temp_buffers = 1000MB;

Doit être le premier appel aux objets temporaires dans votre session. Ne le réglez pas à un niveau élevé à l'échelle mondiale, juste pour votre session. Une table temporaire est supprimée automatiquement à la fin de votre session de toute façon.

Pour obtenir une estimation de la quantité de RAM dont vous avez besoin, créez le tableau une fois et mesurez :

SELECT pg_size_pretty(pg_total_relation_size('tmp_orders'));

Plus d'informations sur la taille des objets sous cette question connexe sur dba.SE .

Tous les frais généraux ne sont payés que si vous devez traiter un certain nombre de requêtes au cours d'une même session. Pour les autres cas d'utilisation, il existe d'autres solutions. Si vous connaissez la table source au moment de la requête, il serait beaucoup plus rapide de diriger votre requête vers la table source à la place. Si vous ne le faites pas, je remettrais en question l'unicité de votre order_nr une fois de plus. S'il est, en fait, garanti d'être unique, vous pouvez supprimer la colonne source J'ai présenté.

Pour une ou quelques requêtes seulement, il peut être plus rapide d'utiliser la vue au lieu de la vue matérialisée.

Je considérerais également une fonction plpgsql qui interroge une table après l'autre jusqu'à ce que l'enregistrement soit trouvé. Peut-être moins cher pour quelques requêtes, compte tenu des frais généraux. Index pour chaque table nécessaire bien sûr.

Aussi, si vous vous en tenez au text ou varchar pour votre order_nr , considérez COLLATE "C" pour cela.