【问题标题】:Compare Rows in oracle table and update matching ones比较oracle表中的行并更新匹配的行
【发布时间】:2017-09-25 04:33:26
【问题描述】:

我有一张如下表:

**ID      tDate        Product    Price    Quantity    BuySell    Status**
  1     10-May-17       pppp       $12        20         Buy       Null
  2     12-May-17       tttt       $10        20         Sell      Null
  3     12-May-17       tttt       $10        20         Buy       Null
  4     18-May-17       pppp       $14        20         Sell      Null
  5     18-May-17       pppp       $14        20         Buy       Null
  6     18-May-17       pppp       $14        20         Sell      Null

我需要更新名为 STATUS 的字段,并将其设置为“匹配”,只要找到具有相同 tDate、产品、价格和数量且不等于 BuySell 的货币对。

以下是想要的结果:

**ID      tDate        Product    Price    Quantity    BuySell    Status**
  1     10-May-17       pppp       $12        20         Buy       Null
  2     12-May-17       tttt       $10        20         Sell      Matched
  3     12-May-17       tttt       $10        20         Buy       Matched
  4     18-May-17       pppp       $14        20         Sell      Matched
  5     18-May-17       pppp       $14        20         Buy       Matched
  6     18-May-17       pppp       $14        20         Sell      Null

注意#6 是如何不匹配的,因为它只能与另一个 null 匹配。

我希望我可以用一条 SQL 语句来执行此操作。

我现在正在做的可能是最糟糕的方法: 我在 python 中加载到 pandas 数据框,然后循环遍历每一行来比较它们。

s = "SELECT ID, Account, product, Price, tDate, BuySell, Qty" + \
    "FROM Table " + \
    "WHERE Status IS NULL " + \
    "ORDER BY Account, product, tDate, Price, Qty"

df = pd.read_sql(s, conn)

for i in range(len(df.index)-1):

    if df.iloc[i, 1] == df.iloc[i+1, 1]  \
        and df.iloc[i, 2] == df.iloc[i+1, 2] \
        and df.iloc[i, 3] == df.iloc[i+1, 3] \
        and df.iloc[i, 4] == df.iloc[i+1, 4] \
        and df.iloc[i, 5] != df.iloc[i+1, 5] \
        and df.iloc[i, 6] == df.iloc[i+1, 6]:

        s = "UPDATE Temp_Fees " + \
            "SET Strategy = 'UNALLOCATED \ CANCELLED' " + \
            "WHERE ID = " + str(df.iloc[i,0]) + \
            " OR ID = " + str(df.iloc[i + 1, 0])

        #custom function that will execute and commit statement
        bb.EXECUTE(s)

        #avoid reading a matched row 
        i = i + 1

谢谢

【问题讨论】:

  • 每个日期可以有超过一对的买卖吗?
  • @vkp 是的,甚至在示例中(记录 4、5、6)。编辑:我承认,该示例并未明确表明每天可以有多个匹配项,但连同描述“#6 不匹配,因为它只能与另一个 null 匹配”一起,它确实隐含地这么说。
  • 编辑问题并解释当键之间存在重复时该怎么办。

标签: python sql oracle pandas plsql


【解决方案1】:
merge into mytable t3
using (select t1.*, count(*) over (partition by tdate,product,price,quantity,field) as field2 from
(
select mytable.*, row_number() over (partition by mytable.tdate,mytable.product,mytable.price,mytable.quantity,mytable.buysell 
order by id) field from 
mytable) t1)  t2
on (t2.id=t3.id and t2.field2='2')
when matched then 
update set status='Matched';

【讨论】:

    【解决方案2】:

    这是另一个可以添加到其他观点的观点。这仅解决匹配部分而不是更新或合并部分。我最近遇到了类似的问题,我需要找到与交易日期和地点匹配的记录,但来自两个不同的来源。在这种情况下,记录必须已经排序,以便类似的记录将放在一起。内部查询将记录与之前和之后的记录进行比较,如果它们匹配,则获取它。然后外部查询确定它们是否满足“差异”标准。希望这会有所帮助。

    select sbs.trnsid, sbs.amount, sbs.transaction_date, sbs.posted_date, sbs.srcid, 
            sbs.credited_flag, sbs.accid, sbs.compid, sbs.badgeid, sbs.locid, sbs.date_credited, 
            sbs.searchable, sbs.priortime, sbs.nexttime, sbs.priorsource, sbs.nextsource 
        from 
        (select trnsid, amount, transaction_date, posted_date, srcid, credited_flag,
          accid, compid, badgeid, locid, date_credited, transaction_date||locid as searchable,
          lag(transaction_date||locid, 1) over (order by accid) as priortime,
          lead(transaction_date||locid, 1) over (order by accid) as nexttime, 
        lag(srcid, 1) over (order by accid) as priorsource, 
        lead(srcid, 1) over (order by accid) as nextsource
        from transactions_table
        where accid = v_acct
          and transaction_date >= to_date('10/01/2016 00:00:00', 'mm/dd/yyyy hh24:mi:ss') 
          and transaction_date <= to_date('04/23/2017 23:59:59', 'mm/dd/yyyy hh24:mi:ss')
          and srcid in ('B', 'S') order by accid, transaction_date, locid) sbs
        where (sbs.searchable = sbs.nexttime and sbs.srcid = 'S' and sbs.nextsource = 'B')
       or (sbs.searchable = sbs.priortime and sbs.srcid = 'B' and sbs.priorsource = 'S');
    

    【讨论】:

      【解决方案3】:

      您可以获得每个 tdate 的买卖对数量并更新这些行。

      MERGE INTO tablename dst
      USING (select t.*,count(*) over(partition by tDate,Product,Price,Quantity,rn) as cnt 
             from (select t.*,row_number() over(partition by tDate,Product,Price,Quantity,buysell order by id) as rn
                   from tablename t) t
             ) src
      ON (src.id = dst.id AND src.cnt=2)
      WHEN MATCHED THEN
      UPDATE SET Status = 'Matched';
      

      运行此查询以查看如何将行号分配给买卖。

      select t.*,count(*) over(partition by tDate,Product,Price,Quantity,rn) as cnt 
      from (select t.*,row_number() over(partition by tDate,Product,Price,Quantity,buysell order by id) as rn
            from tablename t) t
      

      【讨论】:

        【解决方案4】:

        未经测试,但仅使用 SQL:

        MERGE INTO your_table dst
        USING (
          SELECT ROW_NUMBER() OVER (
                     PARTITION BY tDate, Product, Price, Quantity, BuySell
                     ORDER BY ID
                   ) AS idx,
                 COUNT( CASE BuySell WHEN 'Buy' THEN 1 END ) OVER (
                     PARTITION BY tDate, Product, Price, Quantity
                   ) AS num_buy,
                 COUNT( CASE BuySell WHEN 'Sell' THEN 1 END ) OVER (
                     PARTITION BY tDate, Product, Price, Quantity
                   ) AS num_sell
          FROM   your_table
        ) src
        ON ( src.ROWID = dst.ROWID AND src.idx <= LEAST( src.num_buy, src.num_sell ) )
        WHEN MATCHED THEN
          UPDATE SET Status = 'Matched';
        

        【讨论】:

        • 谢谢!我测试了它,但出了点问题。匹配的行太多,没有具有相同数据、价格、数量和产品的偏移行。
        • @Kelaref 我在前 5 分钟内做了一个小编辑,在第二个 COUNT 语句中将 'Buy' 的一个实例更改为 'Sell'。您是在原始版本还是当前版本上进行测试的?
        • 这很漂亮。你介意解释一下它是如何工作的吗?这对我来说太陌生了。
        • 第一次计数给出了每组日期/产品/价格/数量的购买项目数量;第二个计数给出了每组的销售物品数量;并且行号只是分别枚举它们 1、2、3 等,以便在每个组内进行买卖。 LEAST( num_buy, num_sell ) 给出两个值中的较低值,并确定每个组有多少对。然后只需过滤表以仅匹配idx 小于或等于匹配对数的那些行。
        • MERGE 可用于组合INSERTUPDATE 语句 - 这里它仅用于UPDATE 在找到一行时更改状态(匹配ROWID pseudocolumn ) 这是一个匹配的买入/卖出对。
        猜你喜欢
        • 1970-01-01
        • 2015-12-23
        • 2017-06-03
        • 2015-08-04
        • 2021-08-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多