"复"具有多个条件的查询(BEGINNER)

时间:2017-03-10 11:52:37

标签: sql postgresql

我基本上对(postgre)SQL很新,并且必须为以下场景编写一个查询。我敢打赌,对于经验丰富的会员来说,这几乎是可笑的,但请耐心等待我(我现在甚至没有数据库来测试它)。

为每个用户显示一个查询(type = a): 最后一个积极的(成功的)"请求" (request_id,creation_date,amount), 总和"金额"所有失败的"请求", 正面和负面请求的比率。

给出两个表:   user_account - 包含用户列的唯一帐户:account_id(类型:int8,键列,IS_NULLABLE:NO),creation_date(类型:timestamp),account_type(类型:varchar,可能值:{a, b})
请求 - 包含每个请求:request_id(int8,key列,IS_NULLABLE:NO)creation_date(timestamp),account_id(int8),amount(float8),type(类型:varchar,可能值{positiv,否定})

所以我理解的是我可以将两个表与join语句结合在一起,如:

SELECT request.request_id,
request.creation_date, request.amount 
From user_account
INNER JOIN request ON (user_account.account_id = request.account_id)
Where request.type = POSITIV AND account_type = a;
SELECT sum(request.amount) as failed_amount
From user_account
INNER JOIN request ON (user_account.account_id = request.account_id)
Where request.type = NEGATIV AND account_type = a;            
  1. 如果这是正确的,我如何将它们加入一个查询? (我读过子查询并将第二个select语句放在WHERE子句中?)
  2. 对于比率我猜,我必须计算()正面和负面的请求并将它们分开,但老实说,我不知道如何在这种情况下实现它。
  3. 如果有人能给我一个简短的演练,我会非常高兴和感激。

1 个答案:

答案 0 :(得分:0)

tl; dr 最后的代码块应该给你想要的东西,稍加一些改动,使它在postgre中工作

使用子查询是一个更中间的主题,因此如果您没有获得它,请不要气馁。我将在几个步骤中引导您完成它。

(1)组成一些测试数据并连接表

(2)选择最近的积极请求

(3)选择Negativ金额总和

(4)选择积极与否定的比率


测试数据和参考

对于这个答案,我将使用下表作为测试数据:

#user_account
+ ---------- + ------------- + ------------ +
| account_id | creation_date | account_type | 
+ ---------- + ------------- + ------------ +
| 1          | 2016-02-14    | B            |
| 2          | 2016-02-14    | A            |
| 3          | 2016-04-06    | B            |
| 4          | 2016-04-29    | B            |
| 5          | 2016-09-03    | A            |
+ ---------- + ------------- + ------------ +

#request
+ ---------- + ------------- + ---------- + ------- + ------------ +
| request_id | creation_date | account_id | amount  | request_type | 
+ ---------- + ------------- + ---------- + ------- + ------------ +
| 1          | 2016-03-08    | 1          | 4308.02 | positiv      |
| 2          | 2016-04-08    | 1          | 1718.56 | negativ      |
| 3          | 2016-03-11    | 2          | 911.50  | positiv      |
| 4          | 2016-03-12    | 2          | 38.42   | negativ      |
| 5          | 2016-03-12    | 2          | 110.12  | positiv      |
| 6          | 2016-05-08    | 3          | 1843.19 | positiv      |
| 7          | 2016-09-12    | 4          | 7234.11 | negativ      |
| 8          | 2016-10-12    | 4          | 515.51  | negativ      |
| 9          | 2016-10-12    | 5          | 0.01    | positiv      |
| 10         | 2016-10-18    | 5          | 13.02   | positiv      |
+ ---------- + ------------- + ---------- + ------- + ------------ +

我将使用table aliasing,并且我已将请求表中的类型字段重命名为request_type。哦,还有一件事:这是用SQL Server编写的,但它只适用于postgre,只需稍作修改:)

从简单开始,让我们将表连接在一起并过滤account_type

select *
    from #user_account u
    inner join #request r on r.account_id = u.account_id
    where u.account_type = 'A'

给出了下表,我将其作为参考

+ ---------- + ------------- + ------------ + ---------- + ------------- + ------ + ------------ +
| account_id | creation_date | account_type | request_id | creation_date | amount | request_type |
+ ---------- + ------------- + ------------ + ---------- + ------------- + ------ + ------------ +
| 2          | 2016-02-14    | A            | 3          | 2016-03-11    | 911.5  | positiv      |
| 2          | 2016-02-14    | A            | 4          | 2016-03-12    | 38.42  | negativ      |
| 2          | 2016-02-14    | A            | 5          | 2016-03-12    | 110.12 | positiv      |
| 5          | 2016-09-03    | A            | 9          | 2016-10-12    | 0.01   | positiv      |
| 5          | 2016-09-03    | A            | 10         | 2016-10-18    | 13.02  | positiv      |
+ ---------- + ------------- + ------------ + ---------- + ------------- + ------ + ------------ +


选择请求

要理解相关子查询,我们假设我有上表表和变量@account_id = 2。通过查看参考表,我们可以看到对于帐户2,我们想要选择reference_id 5,因为它是最新的positiv请求。以下查询为我们提供了

select top 1 request_id
    from #request
    where account_id = @account_id
        and request_type = 'positiv'
        order by creation_date desc

要在我们的查询中使用此提示,我们需要将@account_id替换为u.account_id,将其转换为相关的子查询,就像这样

select    u.account_id
        , r.request_id
        , r.creation_date
        , r.amount
    from #user_account u
    inner join #request r on r.account_id = u.account_id
    where u.account_type = 'A'
        and r.request_id = (
            select top 1 request_id
                from #request
                where account_id = u.account_id -- correlate to the reference table
                    and request_type = 'positiv'
                order by creation_date desc
        )

它给了我们我们想要的东西

+ ---------- + ---------- + ------------- + ------ +
| account_id | request_id | creation_date | amount |
+ ---------- + ---------- + ------------- + ------ +
| 2          | 5          | 2016-03-12    | 110.12 |
| 5          | 10         | 2016-10-18    | 13.02  |
+ ---------- + ---------- + ------------- + ------ +


选择Negativ金额的总和

我们将在接下来的两个部分中使用相同子查询的相同概念,但是在这里我们将它们放在我们语句的选择部分中,因为我们不再需要过滤掉任何结果。此查询

select    u.account_id
        , r.request_id
        , r.creation_date
        , r.amount
        , ( select isnull(SUM(amount),0) -- replaces a null value with 0
                from #request
                    where account_id = u.account_id
                    and request_type = 'negativ' ) as SumOfFailed
    from ... -- same as above

给我们

+ ---------- + ---------- + ------------- + ------ + ----------- +
| account_id | request_id | creation_date | amount | SumOfFailed |
+ ---------- + ---------- + ------------- + ------ + ----------- +
| 2          | 5          | 2016-03-12    | 110.12 | 38.42       |
| 5          | 10         | 2016-10-18    | 13.02  | 0           |
+ ---------- + ---------- + ------------- + ------ + ----------- +


选择比率

我们在这里基本上做同样的事情,但是在投射和零除检查中可能很容易迷失。所以希望我把它分成足够的线条,以便明确

select    u.account_id
        , r.request_id
        , r.creation_date
        , r.amount
        , (...) as SumOfFailed -- same as above
        , cast(( -- convert integer to float
            select COUNT(*)
                from #request
                where account_id = u.account_id
                    and request_type = 'positiv'
            ) as float)
            / nullif( -- if divisor is zero, return null
            CAST((
                select COUNT(*)
                    from #request
                    where account_id = u.account_id
                        and request_type = 'negativ'
            ) as float), 0) as Ratio
    from ... -- same as above

给了我们

+ ---------- + ---------- + ------------- + ------ + ----------- + ----- +
| account_id | request_id | creation_date | amount | SumOfFailed | Ratio |
+ ---------- + ---------- + ------------- + ------ + ----------- + ----- +
| 2          | 5          | 2016-03-12    | 110.12 | 38.42       | 2     |
| 5          | 10         | 2016-10-18    | 13.02  | 0           | Null  |
+ ---------- + ---------- + ------------- + ------ + ----------- + ----- +


代码块

所以总的来说,你的sql语句将是这样的,有一些细微的差别,使它在postgre中工作。

select u.account_id
        , request_id
        , r.creation_date
        , r.amount
        , ( select isnull(SUM(amount),0) -- replaces a null value with 0
                from #request
                    where account_id = u.account_id
                        and request_type = 'negativ' ) as SumOfFailed
        , cast((
            select COUNT(*)
                from #request
                where account_id = u.account_id
                    and request_type = 'positiv'
            ) as float)
            / nullif(
            CAST((
                select COUNT(*)
                    from #request
                        where account_id = u.account_id
                            and request_type = 'negativ'
            ) as float),0) as Ratio
    from #user_account u
    inner join #request r on r.account_id = u.account_id
    where u.account_type = 'A'
        and r.request_id = (
            select top 1 request_id
                from #request r_sq
                where r_sq.account_id = u.account_id
                    and r_sq.request_type = 'positiv'
                order by creation_date desc
        )

希望这有帮助!