We're Moving!

The Vertica Forum is moving to a new OpenText Analytics Database (Vertica) Community.

Join us there to post discussion topics, learn about

product releases, share tips, access the blog, and much more.

Create My New Community Account Now


Projection with a "WITH" sql clause — Vertica Forum

Projection with a "WITH" sql clause

kfruchtmankfruchtman Vertica Customer

Hi Experts!
Is is possible to create a projection with a WITH clause of sql?
something like this:
CREATE PROJECTION Orders_with_regtime AS
(WITH
registered as (
select min(time) as first_order_time,OrderId from orders group by OrderId),
orders as
(select OrderId,time,C,D,E,F,G,H,I,J from orders)
select orders.OrderId,time,C,D,E,F,G,H,I,J,registered.first_order_time
from registered,orders where
registered.OrderId=orders.OrderId order by registered.first_order_time desc

?

Answers

  • marcothesanemarcothesane - Select Field - Administrator

    Joins are not allowed in a CREATE projection. This also applies to several CTE-s selecting from the same base table.
    It looks like you want to ease the access to the very first timestamp of an order per orderid.

    Try this as a Top-K Live Aggregate projection:

    CREATE PROJECTION orders_first AS
    SELECT
      *
    FROM orders
    LIMIT 1 OVER(PARTITION BY orderid ORDER BY order_time)
    ;
    

    (I would avoid using the reserved word TIME for a column name) ...

  • kfruchtmankfruchtman Vertica Customer

    Thanks for the response!
    But I think I need something else than what you proposed.
    Lets say I have an orders table with many columns and order_time is one of them.I need to add a column which is actually a subquery of the same table and should look for the min(order_time) for each row so I will know for each row the first order ever made.
    So lets say I have a table:orders:
    create table orders (id,order_time,currency,d,h,)
    I want to get a projection : orders (id,order_time.currency,d,h,min(order_time) )
    The min(order_time) column is from the same table and is actually just a query to search for the min(order_time) by id.
    I will explain my needs:.This table is HUGE , so partitioning it and optimizing the query is not enough.Every time I run the query that searches for the min(order_time) for each id it takes forever (25 seconds) for just one day of orders, and I will need to have bigger search criteria like a full month maybe.
    ...so I am looking for a faster solution. I hope I was clear, if not please tell me.
    many thanks!
    Keren

  • marcothesanemarcothesane - Select Field - Administrator

    If you add a column to the table, it would work (and, yes, it has an effect of 8 bytes per row on the audit size)

    Tried this:

    DROP TABLE IF EXISTS public.orders;
    
    CREATE TABLE public.orders (
      orderid INTEGER
    , ordertime TIME
    , amt     NUMERIC(18,4)
    )
    ;
    
    INSERT INTO public.orders
              SELECT 1,TIME '00:01:00', 12.35
    UNION ALL SELECT 1,TIME '00:02:00', 13.35
    UNION ALL SELECT 1,TIME '00:03:00', 13.35
    UNION ALL SELECT 1,TIME '00:04:00', 13.35
    UNION ALL SELECT 1,TIME '00:05:00', 13.35
    UNION ALL SELECT 2,TIME '00:01:00', 13.35
    UNION ALL SELECT 2,TIME '00:02:00', 13.35
    UNION ALL SELECT 2,TIME '00:03:00', 13.35
    UNION ALL SELECT 2,TIME '00:04:00', 13.35
    UNION ALL SELECT 2,TIME '00:05:00', 13.35
    ;
    COMMIT;
    
    ALTER TABLE public.orders
    ADD firstordertime TIME DEFAULT (
      SELECT MIN(o.ordertime) FROM orders o
      WHERE o.orderid=orders.orderid
    );
    
  • marcothesanemarcothesane - Select Field - Administrator

    Someone pointed out to me that you can also use SET USING instead of DEFAULT - with a different effect on the audit size.
    Let's try:

    -- drop and recreate the table ....
    DROP TABLE IF EXISTS public.orders;
    DROP TABLE
    
    CREATE TABLE public.orders (
      orderid INTEGER
    , ordertime TIME
    , amt     NUMERIC(18,4)
    )
    ;
    CREATE TABLE
    -- fill the table ...
    INSERT INTO public.orders
              SELECT 1,TIME '00:01:00', 12.35
    UNION ALL SELECT 1,TIME '00:02:00', 13.35
    UNION ALL SELECT 1,TIME '00:03:00', 13.35
    UNION ALL SELECT 1,TIME '00:04:00', 13.35
    UNION ALL SELECT 1,TIME '00:05:00', 13.35
    UNION ALL SELECT 2,TIME '00:01:00', 13.35
    UNION ALL SELECT 2,TIME '00:02:00', 13.35
    UNION ALL SELECT 2,TIME '00:03:00', 13.35
    UNION ALL SELECT 2,TIME '00:04:00', 13.35
    UNION ALL SELECT 2,TIME '00:05:00', 13.35
    ;
     OUTPUT
    --------
         10
    (1 row)
    -- need to commit to keep the data in the table
    COMMIT;
    COMMIT
    
    -- check the audit size ...
    SELECT AUDIT('public.orders');
     AUDIT
    -------
     160
    (1 row)
    -- add the derived column with "SET USING" and check the audit size again ...
    ALTER TABLE public.orders
    ADD firstordertime_using TIME SET USING (
      SELECT MIN(o.ordertime) FROM orders o
      WHERE o.orderid=orders.orderid
    );
    ALTER TABLE
    SELECT AUDIT('public.orders');
     AUDIT
    -------
     160
    (1 row)
    -- no change. The column is NULL just now.
    -- fill the column by calling "REFRESH_COLUMNS()" ...
    SELECT REFRESH_COLUMNS('public.orders','*');
          REFRESH_COLUMNS
    ---------------------------
     refresh_columns completed
    (1 row)
    COMMIT; -- need committing; it's a DML command.
    COMMIT
    SELECT AUDIT('public.orders');
     AUDIT
    -------
     160
    (1 row)
    -- no change in audit size
    
    -- add the same column once more, but with DEFAULT:
    ALTER TABLE public.orders
    ADD firstordertime_default TIME DEFAULT (
      SELECT MIN(o.ordertime) FROM orders o
      WHERE o.orderid=orders.orderid
    );
    ALTER TABLE
    SELECT AUDIT('public.orders');
     AUDIT
    -------
     240
    (1 row)
    -- And you have 80 bytes more audit size; 8 bytes for each of the 10 rows
    

Leave a Comment

BoldItalicStrikethroughOrdered listUnordered list
Emoji
Image
Align leftAlign centerAlign rightToggle HTML viewToggle full pageToggle lights
Drop image/file