简体   繁体   English

Postgres有条件选择吗?

[英]Postgres Conditional Select?

I'm not really sure how to describe this problem without an example, so here's an example: 我不太确定如何在没有示例的情况下描述此问题,所以这里有一个示例:

I have three tables: 我有三个表:

Table 1: Boxes 表1:盒子

BoxID | Box Name | Box Cost
1 | Bob's Box | $20
2 | Matt's Box | $21
3 | Jacob's Box | $22
4 | Beth's Box | $23
5 | Rachel's Box | $24

Table 2: Box_ProcessIDs 表2:Box_ProcessID

BoxID | ParentProcessID
1 | 123
2 | 456
3 | 789
4 | 012
5 | 234

Table 3: Box_Processes 表3:Box_Processes

ParentProcess | ChildProcess | Start Time | End Time | ProcessName 
123 | AAA | 1:00 | 1:05 | Invoiced
123 | AAB | 1:30 | 1:35 | Packed
123 | BBB | 2:00 | 2:05 | Shipped

456 | CDD | 3:15 | 3:20 | Invoiced
456 | DDD | 3:25 | 3:30 | Packaging_Complete
456 | CCD | 3:35 | 3:40 | Shipped

789 | EEE | 4:15 | 4:20 | Invoiced
789 | EEF | 4:25 | 4:30 | Done_Packing
789 | EFF | 4:35 | 4:40 | Shipped

I want the output columns to be: Box Name, Box Cost, Box Shipping Duration, Box Packing Duration, Box Invoice Duration 我希望输出列为:框名称,框成本,框运输持续时间,框包装持续时间,框发票持续时间

I know I can use like %pack% to select my packing fields, and I can figure out how to use Date_Part or somesuch to get my durations, but I'm at a loss as to how to get my shipping duration , packing duration , and invoice duration into separate fields. 我知道我可以像%pack%一样选择包装字段,并且可以弄清楚如何使用Date_Part或类似的方法来获取工期,但是我对如何获取shipping durationpacking duration ,和invoice duration到单独的字段中。

So you want to do something like this pseudo-sql? 因此,您想执行类似此伪sql的操作吗?

select b.box_name, b.box_cost,
bp2.end_time - bp2.start_time as box_shipping_duration,
bp3.end_time - bp3.start_time as box_packing_duration,
bp1.end_time - bp1.start_time as box_invoice_duration
from boxes b

join box_processids bpid on b.boxid = bpid.boxid

left outer join box_processes bp1 on bpid.parentprocessid = bp1.parentprocess
and processname = 'Invoiced'

left outer join box_processes bp2 on bpid.parentprocessid = bp2.parentprocess
and processname = 'Shipped'

left outer join box_processes bp3 on bpid.parentprocessid = bp3.parentprocess
and processname = 'Packed'

(will need null checks, proper datetime handling, better names and so on) (将需要空检查,正确的日期时间处理,更好的名称等)

First off, your design is flawed. 首先,您的设计存在缺陷。 time is no good for this purpose. time对于这个目的没有好处。 It breaks as soon as you cross midnight. 越过午夜,它就会中断。 Use timestamp or timestamptz instead. 请改用timestamptimestamptz

Next, since unquoted identifiers are cast to lower case automatically in PostgreSQL, your naming convention is no good either. 接下来,由于在PostgreSQL中无引号的标识符会自动转换为小写,因此您的命名约定也不好。 I adapted it to something more useful. 我将其修改为更有用的内容。

CREATE TABLE boxes (box_id int PRIMARY KEY, box_name text, box_cost numeric);
INSERT INTO boxes VALUES
  (1, 'Bob''s Box', 20)
 ,(2, 'Matt''s Box', 21)
 ,(3, 'Jacob''s Box', 22)
 ,(4, 'Beth''s Box', 23)
 ,(5, 'Rachel''s Box', 24);

CREATE TABLE box_processids (
  box_id int 
 ,parentprocess_id int
 ,PRIMARY KEY(box_id, parentprocess_id)
);

INSERT INTO box_processids  VALUES
  (1, 123)
 ,(2, 456)
 ,(3, 789)
 ,(4, 012)
 ,(5, 234);

CREATE TABLE box_processes (
  parentprocess_id int
 ,childprocess_id char(3)
 ,start_time timestamp
 ,end_time timestamp
 ,processname text
 ,PRIMARY KEY(parentprocess_id, childprocess_id)
);

INSERT INTO box_processes VALUES
  (123, 'AAA', '2013-2-10 1:00', '2013-2-10 1:05', 'Invoiced')
 ,(123, 'AAB', '2013-2-10 1:30', '2013-2-10 1:35', 'Packed')
 ,(123, 'BBB', '2013-2-10 2:00', '2013-2-10 2:05', 'Shipped')

 ,(456, 'CDD', '2013-2-10 3:15', '2013-2-10 3:20', 'Invoiced')
 ,(456, 'DDD', '2013-2-10 3:25', '2013-2-10 3:30', 'Packaging_Complete')
 ,(456, 'CCD', '2013-2-10 3:35', '2013-2-10 3:40', 'Shipped')

 ,(789, 'EEE', '2013-2-10 4:15', '2013-2-10 4:20', 'Invoiced')
 ,(789, 'EEF', '2013-2-10 4:25', '2013-2-10 4:30', 'Done_Packing')
 ,(789, 'EFF', '2013-2-10 4:35', '2013-2-10 4:40', 'Shipped');

Your query could then look like this: 您的查询如下所示:

SELECT b.box_name
      ,b.box_cost
      ,(i.end_time - i.start_time) AS box_invoice_duration
      ,(p.end_time - p.start_time) AS box_packing_duration
      ,(s.end_time - s.start_time) AS box_shipping_duration
FROM   boxes               b
LEFT   JOIN box_processids bp USING (box_id)
LEFT   JOIN box_processes  i ON i.parentprocess_id = bp.parentprocess_id
                            AND i.processname = 'Invoiced'
LEFT   JOIN box_processes  p ON i.parentprocess_id = bp.parentprocess_id
                            AND p.processname = 'Packed'
LEFT   JOIN box_processes  s ON i.parentprocess_id = bp.parentprocess_id
                            AND s.processname = 'Shipped'

->sqlfiddle - > sqlfiddle
Use to_char() to format your interval any way you want. 使用to_char()以任意方式设置interval格式。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM