从Oracle

时间:2018-01-10 18:03:53

标签: sql oracle

我有一个由INT(CUSTOMER)类型的多个记录组成的表,需要为帐户的NAME获取最后两个不同的事务。因此,在我的SQL中,我有以下内容提供了最新的4个交易,这些交易都是正确的(我必须选择最新的4条记录,因为,因为您看到选择最新的两条记录会导致两条记录都是NAME' JOHNSON&#39):

SQL> SELECT ID, NAME, DATE, CUSTOMER
    FROM (select * from ORDER_TABLE ORDER BY DATE DESC) ORDER_TABLE
    WHERE rownum <= 4
    and (CUSTOMER = 1002) 
    ORDER BY rownum DESC;

        ID NAME                DATE         CUSTOMER
---------- ------------------- ---------    ----------
        90 SMITH               26-DEC-17    1002
       135 JOHNSON             09-DEC-17    1002
       235 JOHNSON             01-JAN-18    1002
       322 JOHNSON             04-JAN-18    1002

但是,我需要返回的只是最新的DISTINCT NAME命令,所以不过上面的输出,我只想看到:

        90 SMITH               26-DEC-17    1002
       322 JOHNSON             04-JAN-18    1002

我是否可以在单个语句中执行查询以获取所需的输出?任何帮助将不胜感激!!!!

4 个答案:

答案 0 :(得分:0)

这是一种方法 - 使用分析函数。这有点复杂;遗憾的是,count(distinct ...)可以用作分析函数,但只能使用partition by子句 - 而不是order by子句。因此,我们必须使用组启动技术手动创建它。

请注意,WITH子句中的第一个子查询仅用于生成测试数据;如果对实际表使用它,请从代码中删除它,并确保第二个子查询中的表名(和列名!)是正确的。我将列名date替换为dt; date是保留字,不应用作列名。

我正在展示一般解决方案 - 如果需要,您当然可以过滤单个客户编号。 (或者,如果您一次只需要一个客户,则可以稍微简化查询。)

with
  tbl ( id, name, dt, customer ) as (
    select  90, 'SMITH'  , to_date('26-DEC-17', 'dd-MON-rr'), 1002 from dual union all
    select 135, 'JOHNSON', to_date('09-DEC-17', 'dd-MON-rr'), 1002 from dual union all
    select 235, 'JOHNSON', to_date('01-JAN-18', 'dd-MON-rr'), 1002 from dual union all
    select 322, 'JOHNSON', to_date('04-JAN-18', 'dd-MON-rr'), 1002 from dual
  ),
  flg ( id, name, dt, customer, flag ) as (
    select id, name, dt, customer,
           case when lag(name) over (partition by customer order by dt desc) = name
                then null else 1 end
    from   tbl
  ),
  prep ( id, name, dt, customer, sm ) as (
    select id, name, dt, customer,
           sum(flag) over (partition by customer order by dt desc)
    from   flg
  )
select max(id) keep (dense_rank first order by dt desc) as id,
       name, max(dt) as dt, customer
from   prep
where  sm <= 2
group by customer, name
;

        ID NAME    DT          CUSTOMER
---------- ------- --------- ----------
        90 SMITH   26-DEC-17       1002
       322 JOHNSON 04-JAN-18       1002

答案 1 :(得分:0)

在Oracle 12.1及更高版本中,match_recognize能够快速完成这些要求(并且通常比分析函数方法快得多)。

我不会在本答案中写一篇关于match_recognize的完整教程;我只想指出{- ... -}语法中的PATTERN表示这些行是匹配定义的一部分,但这些行是从输出中排除的。其余部分是match_recognize的基本应用。

我正在展示一般解决方案 - 如果需要,您当然可以过滤单个客户编号。 (或者,如果您一次只需要一个客户,则可以稍微简化查询。)

with
  tbl ( id, name, dt, customer ) as (
    select  90, 'SMITH'  , to_date('26-DEC-17', 'dd-MON-rr'), 1002 from dual union all
    select 135, 'JOHNSON', to_date('09-DEC-17', 'dd-MON-rr'), 1002 from dual union all
    select 235, 'JOHNSON', to_date('01-JAN-18', 'dd-MON-rr'), 1002 from dual union all
    select 322, 'JOHNSON', to_date('04-JAN-18', 'dd-MON-rr'), 1002 from dual
  )
select *
from   tbl
match_recognize(
  partition by customer
  order by dt desc
  all rows per match
  pattern ( ^ a {- b* -} c )
  define b as name = a.name
);

  CUSTOMER DT                ID NAME  
---------- --------- ---------- -------
      1002 04-JAN-18        322 JOHNSON
      1002 26-DEC-17         90 SMITH  

答案 2 :(得分:0)

class UdpServer
{
PrintWriter out;
ButtonHandler txButtonHandler;
BufferedReader in;
    DatagramSocket socket;
    InetAddress ip = null;
int port;

    UdpServer (String gport) throws IOException
    {
        int i = 0;
        socket = new DatagramSocket (Integer.parseInt (gport));

  txButtonHandler = new ButtonHandler ();
  sendButton.addActionListener (txButtonHandler);
        new Thread ()
        {
            public void run ()
            {
                try
                {
                    rx ();
                }
                catch (IOException e)
                {
                }
            }

        }.start ();
        tx ();
        System.exit (1);
    }

    void tx () throws IOException
    {
        byte[] buf = new byte[256];
        BufferedReader in = new BufferedReader (new InputStreamReader(System.in));
        String toServer;

        do
        {
            toServer = in.readLine();
            toServer = toServer + "\n";
            buf = toServer.getBytes ();
            DatagramPacket packet = new DatagramPacket (buf, toServer.length(), ip, port);
            if (ip != null) socket.send(packet);
        }
        while (toServer != null);
        socket.close ();
        System.exit (1);
    }

private class ButtonHandler implements ActionListener
{
    public void actionPerformed (ActionEvent event) //throws IOException
    {
        try{tx ();} catch (IOException e){}
    }
}

    void rx () throws IOException
    {
        byte[] buf = new byte[256];
        String fromServer;
        do
        {
            for (int i = 0; i < 256; i ++) buf[i] = 0;
            DatagramPacket packet = new DatagramPacket (buf, buf.length);
            socket.receive (packet);
            fromServer = new String (packet.getData());
            ip = packet.getAddress ();
            port = packet.getPort ();
            //System.out.println (port + ":" + ip);
            if (fromServer != null) System.out.print (fromServer);
        }
        while (fromServer != null);
        socket.close ();
        System.exit (1);
    }
}

答案 3 :(得分:-1)

SELECT id, name, date, customer
FROM   order_table
WHERE  (name, date) IN 
       (SELECT name, max(date)
        FROM   order_table
        WHERE  customer = 1002
        GROUP BY name)
;

当然,使用IN并不是大表中最好的,你可以使用内连接。