查询五个表,包括两个相互关联的联结表以形成View

时间:2015-05-04 12:32:42

标签: postgresql join views

我有三个表(surveypoint,sample,fldwrk_images):一个测量点可以有很多或没有样本,测量点和样本都可以有很多或没有图像,测量点和样本都链接到两个单独的连接表作为图像可以是一个或多个样本/测量点。这两个多对多关系由连接表fldwrk_images的两个联结表(svypnt_fldwrk_image_junc和sample_fldwrk_image_junc)组成。

我正在尝试创建一个视图,该视图将导致每行包含测量点信息,与测量点相关的样本信息(如果有)和图像信息(如果有)。由于图像来自连接表,我期望在测量点和样本上有重复信息,这很好,但我希望视图在image_id上​​是不同的。

以下是我在查询时的尝试,当运行永远持续时,显然它是有缺陷的,我无法弄清楚如何做到这一点。

CREATE OR REPLACE VIEW query_fldwrk_images_by_surveypoint_and_sample AS 
SELECT DISTINCT ON (fi1.fldwrk_image_id) svypnt_fldwrk_image_junc.svypnt_fldwrk_image_junc_id,
fi1.image_path,
fi1.image_name,
fi1.iptc_caption,
fi1.iptc_keywords,
srpnt1.surveypoint_name,
fi1.fldwrk_image_id,
sam1.sample_name
FROM surveypoint as srpnt1
LEFT JOIN sample sam2 ON srpnt1.surveypoint_id = sam2.surveypoint_id,
svypnt_fldwrk_image_junc
LEFT JOIN fldwrk_image fi1 ON svypnt_fldwrk_image_junc.fldwrk_image_id = fi1.fldwrk_image_id
LEFT JOIN surveypoint srpnt2 ON svypnt_fldwrk_image_junc.surveypoint_id = srpnt2.surveypoint_id,
sample_fldwrk_image_junc
LEFT JOIN fldwrk_image fi2 ON sample_fldwrk_image_junc.fldwrk_image_id = fi2.fldwrk_image_id
LEFT JOIN sample sam1 ON sample_fldwrk_image_junc.sample_id = sam1.sample_id;

2 个答案:

答案 0 :(得分:1)

CROSS JOIN

问题是这个

FROM surveypoint as srpnt1
LEFT JOIN sample sam2 ON srpnt1.surveypoint_id = sam2.surveypoint_id

不以任何方式加入此

svypnt_fldwrk_image_junc
LEFT JOIN fldwrk_image fi1 ON svypnt_fldwrk_image_junc.fldwrk_image_id = fi1.fldwrk_image_id
LEFT JOIN surveypoint srpnt2 ON svypnt_fldwrk_image_junc.surveypoint_id = srpnt2.surveypoint_id

并且都没有加入此

sample_fldwrk_image_junc
LEFT JOIN fldwrk_image fi2 ON sample_fldwrk_image_junc.fldwrk_image_id = fi2.fldwrk_image_id
LEFT JOIN sample sam1 ON sample_fldwrk_image_junc.sample_id = sam1.sample_id

(请注意,surveypointsample上的表别名不同。)这会创建CROSS JOIN,从而产生三组表的笛卡尔积。如果每个组有1,000条记录,则视图将有1,000,000,000条记录,这需要一些时间来准备。

更改samplesurveypoint上的别名,重新排列加入顺序可以让您的视图快速准备。

DISTINCT ON

您注意到您希望视图为DISTINCT ONimage_id关联的surveypoint。这里有几点需要考虑:

  • 除非您包含ORDER BY子句,否则视图中保留的记录是不确定的,即使针对视图的单独查询可能会显示不同的结果。
  • 显然,surveypoint可以包含许多图片,并且图片可以与surveypoint及其任何sample相关联。精细。但是,单个图像可以与多个surveypoint s相关联吗?这听起来不太符合逻辑。

重新描述你的叙述(并根据你在问题中的查询添加一些似乎有意义的猜测),看起来你想要这个(在伪SQL中):

CREATE VIEW query_fldwrk_images_by_surveypoint_and_sample AS
  SELECT surveypoint_info, sample_info, image_info
  WHERE image_info IS ANY image_info LINKED TO svy_pnt
  OR ELSE ANY image_info LINKED TO ANY smpl LINKED TO svy_pnt NOT USED IN OTHER RECORDS

由于两条路径上的多对多关系以及DISTINCT ON image_id的要求,无法以确定的方式在简单查询中执行此操作。简而言之,问题是您必须创建surveypoint-sample-image的组合并跟踪您分配的图像,如果您在某处遇到NULL,可能会回溯(例如,您可以拥有{ {1}}没有与之关联的图片,因此您使用第一个可用surveypoint的图像。如果任何其他样本只有该图像链接到它,它将会出现没有有效图像(因为sample子句,而在其他样本中可能有"额外"图像。)

您应该放宽DISTINCT ON要求,使其成为一个相对简单的视图。这样的放松可以是这样的形式:给所有测量点提供他们的样本和测量点的图像;如果图像为DISTINCT ON,请使用采样点的任何图像。您可能会得到来自不同样本的相同图像,但至少您会看到自己的观点。

我可以看到这可能有用的唯一方法是扭转逻辑:而不是将图像链接到测量点和样本,将后者链接到图像,但是你会遇到很多相同的问题对多个冲突(即哪个调查点或样本分配给哪个图像)。递归CTE会做很多努力,但解决冲突仍然会非常困难。

答案 1 :(得分:1)

(我正在回答我自己的问题,以便对我的新数据库结构进行回复/评论:我不确定这个礼节......)

基于Patrick提供的第一个答案,似乎我的数据库结构化,我无法查询它以提取我需要的信息。为了解决这个问题,我重新构建了数据库,使两个连接表将三个表连接到一个连接三个表的连接表,新的连接表具有一个junction_pk,一个image_id,一个surveypoint_id和一个sample_id。由于某些测量点没有关联的样本,因此在新的联结表中有一些行没有sample_id数据。

为了提取我需要的所有信息,我首先在测量点上的junction_id上使用select distinct创建一个视图,首先使用sample_id为null然后sample_id上​​的union不为null(这似乎是必需的,否则测量点上的数据与没有相关的样本显示为空,因为没有办法说sample_id彼此相关)。

新结构似乎有效,并且在我所需的视图中不会产生错误的连接(该视图基于另一个查询 - query.1 - 它首先查询六个表以汇集与图像关联所需的信息)。

我的问题是:这种联结表连接三个表在数据库中的良好实践:这会导致我不知道的问题吗?我是否通过使用适当/有效的union方法创建视图?

查询是:

CREATE OR REPLACE VIEW query_surv_sam_images_irll14 AS 
     SELECT DISTINCT ON (junc1.svy_sam_image_junc_id) fi1.iptc_caption,
        query1.surveypoint_name,
        query1.sample_name,
        query1.material_name,
        query1.surv_formation_name,
        query1.surv_newcode,
        query1.samp_formation_name,
        query1.samp_newcode,
        query1.surveypoint_type_name,
        query1.surveypoint_descrp_brief,
        query1.surveypoint_description,
        query1.survey_date,
        query1.sample_type_name,
        query1.geochemical,
        query1.outcrop_grp_name,
        query1.outcrop_grp_descrp,
        query1.locality_name,
        query1.area_name,
        query1.waterbasin_name,
        query1.townland_name,
        query1.county,
        query1.country_name,
        junc1.svy_sam_image_junc_id,
        junc1.surveypoint_id,
        query1.surv_id,
        junc1.sample_id,
        query1.samp_id,
        fi1.image_name,
        fi1.image_path,
        fi1.geom
       FROM svy_sam_image_junc junc1
  JOIN fldwrk_image fi1 ON fi1.fldwrk_image_id = junc1.fldwrk_image_id
   LEFT JOIN query_srpnts_samples_irll14 query1 ON query1.surv_id = junc1.surveypoint_id
  WHERE junc1.sample_id IS NULL
UNION
     SELECT DISTINCT ON (junc1.svy_sam_image_junc_id) fi1.iptc_caption,
        query1.surveypoint_name,
        query1.sample_name,
        query1.material_name,
        query1.surv_formation_name,
        query1.surv_newcode,
        query1.samp_formation_name,
        query1.samp_newcode,
        query1.surveypoint_type_name,
        query1.surveypoint_descrp_brief,
        query1.surveypoint_description,
        query1.survey_date,
        query1.sample_type_name,
        query1.geochemical,
        query1.outcrop_grp_name,
        query1.outcrop_grp_descrp,
        query1.locality_name,
        query1.area_name,
        query1.waterbasin_name,
        query1.townland_name,
        query1.county,
        query1.country_name,
        junc1.svy_sam_image_junc_id,
        junc1.surveypoint_id,
        query1.surv_id,
        junc1.sample_id,
        query1.samp_id,
        fi1.image_name,
        fi1.image_path,
        fi1.geom
       FROM svy_sam_image_junc junc1
  JOIN fldwrk_image fi1 ON fi1.fldwrk_image_id = junc1.fldwrk_image_id
   LEFT JOIN query_srpnts_samples_irll14 query1 ON query1.samp_id = junc1.sample_id
  WHERE junc1.sample_id IS NOT NULL
  ORDER BY 2, 3, 1, 28;