我正在使用实体 - 属性 - 值(EAV)模式来存储目标对象的“覆盖”。也就是说,有三个表:
我想要做的是选择Overrides以及Entity表中''overridden'列的值。因此,需要动态使用SQL中的属性名称。
我在(PostgreSQL)SQL中的天真尝试:
SELECT
OV.entity_id as entity,
AT.name as attribute,
OV.value as value,
ENT.base_value as base_value
FROM "override" AS OV
LEFT JOIN "attribute" as AT
ON (OV.attribute_id = AT.id)
LEFT JOIN LATERAL (
SELECT
id,
AT.name as base_value -- AT.name doesn't resolve to a SQL identifier
FROM "entity"
) AS ENT
ON ENT.id = OV.entity_id;
这不起作用,因为AT.name
没有解析为SQL标识符,只返回列名,例如'col1','col2'等,而不是使用列名查询实体。
我知道这是动态SQL,但我对PL / pgSQL很新,并且因为它是相关/横向连接而无法弄清楚。另外,这是否可能,因为色谱柱类型不均匀?请注意,覆盖表中的所有“值”都存储为字符串以解决此问题。
非常感谢任何帮助!
答案 0 :(得分:2)
您可以使用PL / pgSQL动态请求列。我假设以下简化的数据库结构(所有原始值和覆盖值都是"字符变化"在此示例中,因为我没有找到任何其他类型信息):
CREATE TABLE public.entity (
id integer NOT NULL DEFAULT nextval('entity_id_seq'::regclass),
attr1 character varying,
attr2 character varying,
<...>
CONSTRAINT entity_pkey PRIMARY KEY (id)
)
CREATE TABLE public.attribute (
id integer NOT NULL DEFAULT nextval('attribute_id_seq'::regclass),
name character varying,
CONSTRAINT attribute_pkey PRIMARY KEY (id)
)
CREATE TABLE public.override (
entity_id integer NOT NULL,
attribute_id integer NOT NULL,
value character varying,
CONSTRAINT override_pkey PRIMARY KEY (entity_id, attribute_id),
CONSTRAINT override_attribute_id_fkey FOREIGN KEY (attribute_id)
REFERENCES public.attribute (id),
CONSTRAINT override_entity_id_fkey FOREIGN KEY (entity_id)
REFERENCES public.entity (id))
使用PL / pgSQL函数
create or replace function get_base_value(
entity_id integer,
column_identifier character varying
)
returns setof character varying
language plpgsql as $$
declare
begin
return query execute 'SELECT "' || column_identifier || '" FROM "entity" WHERE "id" = ' || entity_id || ';';
end $$;
您几乎可以使用您的查询:
SELECT
OV.entity_id as entity,
AT.name as attribute,
OV.value as value,
ENT.get_base_value as base_value
FROM "override" AS OV
LEFT JOIN "attribute" as AT
ON (OV.attribute_id = AT.id)
LEFT JOIN LATERAL (
SELECT id, get_base_value FROM get_base_value(OV.entity_id, AT.name)
) AS ENT
ON ENT.id = OV.entity_id;