динамическое объединение на основе содержимого выбранного столбца (postgres) - PullRequest
1 голос
/ 24 октября 2019

Этот вопрос для postgres, но я знаю только, как написать базовый mySQL, поэтому, пожалуйста, простите за любой неправильный синтаксис в моем объяснении. (переходя на другую технологию (монго), нужно знать, может ли postgres приспособиться).

Вот несколько примеров таблиц:

table ``profile``
+---------------------------------------+
| id  | name       | ver   | os | os_id |
+---------------------------------------+
| 221 | test1      | 0.0.1 | 1  | 12    |
| 222 | test2      | 0.0.2 | 2  | 13    |
| 223 | helloworld | 1.0.0 | 2  | 12    |
+---------------------------------------+

table ``linux``
+------------------------+
| id  | distro | env     |
+------------------------+
| 12  | arch   | openbox |
| 13  | debian | kde     |
+------------------------+

table ``windows``
+-----------------------+
| id | release    | sp  |
+-----------------------+
| 8  | Windows 8  | sp1 |
| 9  | Windows 10 | sp2 |
+-----------------------+

table ``android``
+---------------------------------+
| id | release     | image | root |
+---------------------------------+
| 12 | lollipop    | uri   | 1    |
| 13 | marshmallow | uri   | 0    |
+---------------------------------+

table ``oslist``
+--------------+
| id | name    |
+--------------+
| 1  | android |
| 2  | linux   |
| 3  | windows |
+--------------+

Основной запрос извлекает конкретную строку из таблицы профиля,в этом примере id 223:

SELECT profile.id, profile.name, profile.ver, profile.os, profile.os_id FROM profile WHERE profile.id=223 ...

Но мне также нужно добавить данные строки из соответствующей операционной системы в результат. Это не идеально, чтобы сделать второй запрос, поэтому я хотел бы это как подзапрос или JOIN.

Так что в том же примере, запрос должен понять , что profile.os равен 2и проверить table.oslist для идентификатора 2, увидеть, что это linux, а затем использовать это имя для динамического присоединения к соответствующей таблице: JOIN linux ON linux.id = profile.os_id

Результат будеттогда будьте так:

+---------------------------------------+
| name       | ver   | distro | env     |
+---------------------------------------+
| helloworld | 1.0.0 | arch   | openbox |
+---------------------------------------+

Если бы идентификатор профиля был 221, результат был бы таким:

+----------------------------------------------+
| name       | ver   | release  | image | root |
+----------------------------------------------+
| test1      | 0.0.1 | lollipop | uri   | 1    |
+----------------------------------------------+

Возможно ли это? Требуется ли использование таблицы oslist или может быть какая-то другая предварительно написанная функция, в которую она может быть передана (например, в виде переключателя)?

Спасибо!

1 Ответ

1 голос
/ 25 октября 2019

Ни один запрос не может вернуть различное количество столбцов. Однако вы можете включить все возможные значения или вернуть результаты в виде JSON. С другой стороны, у вас есть ограниченное количество различных ОС, поэтому это выполнимо.

SELECT
  profile.name, profile.ver,
  oslist.name AS os,
  android.release AS android_release, android.image, android.root,
  linux.distro, linux.env,
  windows.release AS windows_release, windows.sp
FROM profile
  LEFT JOIN oslist ON (oslist.id = profile.os)
  LEFT JOIN android ON (profile.os = 1 AND android.id = profile.os_id)
  LEFT JOIN linux ON (profile.os = 2 AND linux.id = profile.os_id)
  LEFT JOIN windows ON (profile.os = 3 AND windows.id = profile.os_id)
WHERE profile.id = 223

Для вывода в формате JSON попробуйте следующее:

SELECT
  jsonb_strip_nulls(
    jsonb_build_object(
      'name', profile.name,
      'version', profile.ver,
      'os', oslist.name,
      'release', coalesce(android.release, windows.release),
      'image', android.image,
      'root', android.root,
      'distro', linux.distro,
      'env', linux.env,
      'sp', windows.sp
    )
  ) AS result
FROM profile
  LEFT JOIN oslist ON (oslist.id = profile.os)
  LEFT JOIN android ON (profile.os = 1 AND android.id = profile.os_id)
  LEFT JOIN linux ON (profile.os = 2 AND linux.id = profile.os_id)
  LEFT JOIN windows ON (profile.os = 3 AND windows.id = profile.os_id)
WHERE profile.id=223

Это даст вам

+----------------------------------------------------------------------------------+
| result                                                                           |
+----------------------------------------------------------------------------------+
| { "name": "helloworld", "version": "1.0.0", "distro": "arch", "env": "openbox" } |
+----------------------------------------------------------------------------------+
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...