Slow query with WITH and JOIN

Hi,
This code is taking too much time to complete :
WITH rawData AS -- 563 rows in 0.07s OR 59 rows in 0.02s
SELECT
     date_releve AS x1,
     index_corrige AS y1,
     LEAD(date_releve) OVER (PARTITION BY id_compteur ORDER BY date_releve) AS x2,
     LEAD(index_corrige) OVER (PARTITION BY id_compteur ORDER BY date_releve) AS y2,
     id AS id_releve,
     id_compteur
FROM V_relevesCorriges
meteoData AS -- 1082 rows in 1.34s OR 116 rows in 0.16s
SELECT avg(meteo.valeur) AS meteoValue, x2 AS dateMeteo, id_variable, id_releve, id_compteur
FROM meteo, rawData
WHERE date_meteo <= x2 AND date_meteo > x1
GROUP BY id_releve, id_variable, x2, id_compteur
ORDER BY x2
consoData AS -- 1104 rows in 1.43s, 117 rows in 0.2s
SELECT
to_char(x1, 'DD.MM.YYYY') || ' - ' || to_char(x2, 'DD.MM.YYYY') AS periode,
     meteoValue AS meteo_moyenne,
     (y2 - y1) / nullif((x2 - x1),0) AS conso_par_jour,
     (y2 - y1) AS conso,
     rawData.id_releve id_releve,
     meteoData.id_variable id_variable,
     meteoData.id_compteur id_compteur
FROM rawData LEFT OUTER JOIN meteoData ON rawData.id_releve = meteoData.id_releve
ORDER BY x2
SELECT periode, meteo_moyenne, conso_par_jour, consoData.id_variable id_variable, consoData.id_releve id_releve, id_compteur -- 1104 rows in 1.51s, 116 rows in 1.34s
FROM consoData LEFT OUTER JOIN diagnostic2 ON consoData.id_releve = diagnostic2.id_releve AND consoData.id_variable = diagnostic2.id_variable
WHERE Id_compteur = 4If I remove "WHERE Id_compteur = 4" on the last line, it makes almost no difference in execution time. Without this WHERE clause, it returns 1104 rows in 1.51s, with it it returns 116 rows in 1.34s.
I'm saying that it takes too long because when I move this WHERE clause into "consoData" (WHERE meteoData.consoData=4), it returns 116rows in 0.2s, for getting the same data output. If I remove the LEFT OUTER JOIN diagnostic2 (last but one line) it also takes 0.2s.
I think that the solution would be to force "WHERE Id_compteur=..." to take effect before it joins the "diagnostic2" table, but don't know how to do it.
The subquery that takes much time when returning all rows is "meteoData".
This code is meant to be a VIEW, so "WHERE Id_compteur=..." will not be included in it but passed when querying the view. I tested it as a VIEW, same problem.
Explain plan :
Plan hash value: 724835998
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
| 0 | SELECT STATEMENT | | 16364 | 1342K| | 586 (4)| 00:00:08 |
| 1 | TEMP TABLE TRANSFORMATION | | | | | | |
| 2 | LOAD AS SELECT | DIAGNOSTIC2 | | | | | |
| 3 | WINDOW SORT | | 563 | 15764 | | 12 (25)| 00:00:01 |
| 4 | VIEW | V_RELEVESCORRIGES | 563 | 15764 | | 11 (19)| 00:00:01 |
| 5 | SORT GROUP BY | | 563 | 56300 | | 11 (19)| 00:00:01 |
| 6 | VIEW | | 563 | 56300 | | 10 (10)| 00:00:01 |
|* 7 | HASH JOIN RIGHT OUTER | | 563 | 25335 | | 10 (10)| 00:00:01 |
| 8 | TABLE ACCESS FULL | COMPTEURS | 22 | 132 | | 3 (0)| 00:00:01 |
| 9 | VIEW | | 563 | 21957 | | 7 (15)| 00:00:01 |
|* 10 | HASH JOIN OUTER | | 563 | 26461 | | 7 (15)| 00:00:01 |
| 11 | TABLE ACCESS FULL | RELEVES | 563 | 12949 | | 3 (0)| 00:00:01 |
| 12 | VIEW | V_CORRECTIONDATA | 563 | 13512 | | 3 (0)| 00:00:01 |
|* 13 | VIEW | | 563 | 28150 | | 3 (0)| 00:00:01 |
| 14 | WINDOW SORT | | 563 | 67560 | | 3 (0)| 00:00:01 |
| 15 | VIEW | | 563 | 67560 | | 3 (0)| 00:00:01 |
| 16 | NESTED LOOPS OUTER| | 563 | 14638 | | 3 (0)| 00:00:01 |
| 17 | TABLE ACCESS FULL| RELEVES | 563 | 12949 | | 3 (0)| 00:00:01 |
|* 18 | INDEX UNIQUE SCAN| COMPTEURS_PK | 1 | 3 | | 0 (0)| 00:00:01 |
|* 19 | HASH JOIN RIGHT OUTER | | 16364 | 1342K| | 573 (4)| 00:00:07 |
| 20 | INDEX FULL SCAN | DIAGNOSTIC2_PK | 4 | 24 | | 1 (0)| 00:00:01 |
| 21 | VIEW | | 16364 | 1246K| | 572 (4)| 00:00:07 |
| 22 | SORT ORDER BY | | 16364 | 1661K| 3864K| 572 (4)| 00:00:07 |
|* 23 | HASH JOIN | | 16364 | 1661K| | 179 (9)| 00:00:03 |
| 24 | VIEW | | 1157 | 55536 | | 3 (0)| 00:00:01 |
| 25 | TABLE ACCESS FULL | SYS_TEMP_0FD9D6657_90A96D1D | 1157 | 55536 | | 3 (0)| 00:00:01 |
|* 26 | VIEW | | 7963 | 435K| | 175 (8)| 00:00:03 |
| 27 | SORT GROUP BY | | 7963 | 311K| 1768K| 175 (8)| 00:00:03 |
| 28 | MERGE JOIN | | 26409 | 1031K| | 23 (48)| 00:00:01 |
| 29 | SORT JOIN | | 1157 | 28925 | | 4 (25)| 00:00:01 |
| 30 | VIEW | | 1157 | 28925 | | 3 (0)| 00:00:01 |
| 31 | TABLE ACCESS FULL | SYS_TEMP_0FD9D6657_90A96D1D | 1157 | 55536 | | 3 (0)| 00:00:01 |
|* 32 | FILTER | | | | | | |
|* 33 | SORT JOIN | | 9130 | 133K| | 11 (19)| 00:00:01 |
| 34 | TABLE ACCESS FULL | METEO | 9130 | 133K| | 9 (0)| 00:00:01 |
Predicate Information (identified by operation id):
7 - access("RELEVES"."ID_COMPTEUR"="COMPTEURS"."ID"(+))
10 - access("RELEVES"."ID_COMPTEUR"="V_CORRECTIONDATA"."ID_COMPTEUR"(+))
filter("RELEVES"."DATE_RELEVE">="V_CORRECTIONDATA"."DATE_CHANGEMENT"(+))
13 - filter("CHG_COMPTEUR"=1 AND "ID_COMPTEUR"="ID_COMPTEUR_CORR")
18 - access("RELEVES"."ID_COMPTEUR"="COMPTEURS"."ID"(+))
19 - access("CONSODATA"."ID_VARIABLE"="DIAGNOSTIC2"."ID_VARIABLE"(+) AND
"CONSODATA"."ID_RELEVE"="DIAGNOSTIC2"."ID_RELEVE"(+))
23 - access("RAWDATA"."ID_RELEVE"="METEODATA"."ID_RELEVE")
26 - filter("METEODATA"."ID_COMPTEUR"=4)
32 - filter("DATE_METEO">"X1")
33 - access(INTERNAL_FUNCTION("DATE_METEO")<=INTERNAL_FUNCTION("X2"))
filter(INTERNAL_FUNCTION("DATE_METEO")<=INTERNAL_FUNCTION("X2"))Oracle database version : 10.2.0.4.0, I'm accessing it through APEX version 4.1.1.00.23
I hope that my question is not too fuzzy..

Perhaps you need to push the filter on id_compteur up to the rawdata subquery?
Try:
WITH rawdata
     AS -- 563 rows in 0.07s OR 59 rows in 0.02s
       (SELECT date_releve AS x1,
               index_corrige AS y1,
               LEAD(date_releve)
                 OVER (PARTITION BY id_compteur ORDER BY date_releve)
                 AS x2,
               LEAD(index_corrige)
                 OVER (PARTITION BY id_compteur ORDER BY date_releve)
                 AS y2,
               id AS id_releve,
               id_compteur
        FROM   v_relevescorriges
        WHERE  id_compteur = 4),
     meteodata
     AS -- 1082 rows in 1.34s OR 116 rows in 0.16s
       (SELECT AVG(meteo.valeur) AS meteovalue,
               x2 AS datemeteo,
               id_variable,
               id_releve,
               id_compteur
        FROM   meteo, rawdata
        WHERE  date_meteo <= x2
        AND    date_meteo > x1
        GROUP BY id_releve,
                 id_variable,
                 x2,
                 id_compteur
        ORDER BY x2),
     consodata
     AS -- 1104 rows in 1.43s, 117 rows in 0.2s
       (SELECT TO_CHAR(x1, 'DD.MM.YYYY') || ' - ' || TO_CHAR(x2, 'DD.MM.YYYY')
                 AS periode,
               meteovalue AS meteo_moyenne,
               (y2 - y1) / NULLIF((x2 - x1), 0) AS conso_par_jour,
               (y2 - y1) AS conso,
               rawdata.id_releve id_releve,
               meteodata.id_variable id_variable,
               meteodata.id_compteur id_compteur
        FROM   rawdata
               LEFT OUTER JOIN meteodata
                 ON rawdata.id_releve = meteodata.id_releve
        ORDER BY x2)
SELECT periode,
       meteo_moyenne,
       conso_par_jour,
       consodata.id_variable id_variable,
       consodata.id_releve id_releve,
       id_compteur -- 1104 rows in 1.51s, 116 rows in 1.34s
FROM   consodata
       LEFT OUTER JOIN diagnostic2
         ON consodata.id_releve = diagnostic2.id_releve
         AND consodata.id_variable = diagnostic2.id_variable;

Similar Messages

  • Slow Query only with some values??????

    I have this tables:
    Vehicles: id_vehicle, id_customer, registration_number, model, ... (2.000.000 of records) (1.500.000 distinct id_customer)
    Insurance-Customers-Vehicles: id_insurance, id_customer, id_vehicle ... (4.500.000 of records)
    Insurance: id_insurance, date_insurance, ...
    Customers: id_customer, name, surname, ..
    QUERY:
    select
    vh.id_vehicle,
    vh.id_customer,
    vd.model,
    vd.registration_number
    from Insurance-Customers-Vehicles vh
    left join Vehicles v on (vh.id_vehicle = v.id_vehicle and vh.id_customer = v.id_customer)
    inner join Vehicles vd on (vh.cod_vehiculo = vd.cod_vehiculo)
    where vh.id_customer = 123456
    and vh.id_vehicle is null
    I execute this query because I want to obtain Vehicles that have been associated with a customer but I don’t want to obtain the vehicle-customer on Insurance-Customers-Vehicles table if it’s now associated to the vehicle-customer on vehicles table.
    This query is very fast at 99% of the time (less than 1 second), but when a client has many vehicles associated (more than 50) on Insurance-Customers-Vehicles table the query is very slow and takes between 10 and 20 seconds ...
    Insurance-Customers-Vehicles
    Please, How can I improve it?????
    Thanks in advance!!!!!
    Operation     Object Name                              Rows     Bytes     Cost     Object Node     In/Out     PStart     PStop
    SELECT STATEMENT Optimizer Mode=CHOOSE                         3             12                                          
      NESTED LOOPS                                        3       498       12                                          
        FILTER                                                                
          NESTED LOOPS OUTER                                                                
            TABLE ACCESS BY INDEX ROWID     Insurance-Customers-Vehicles     3       408       6                                          
              INDEX RANGE SCAN     IND_INSCUVEH_ID_CUSTOMER          3             3                                          
            TABLE ACCESS BY INDEX ROWID     VEHICLES               1       13       2                                          
              INDEX UNIQUE SCAN     PK_VEHICLES                    1             1                                          
        TABLE ACCESS BY INDEX ROWID     VEHICLES                    1       17                                                
          INDEX UNIQUE SCAN     PK_VEHICLES                         1             1                  

    I think there is something logically wrong with this query.
    You left join the vehicle table, however you already know that id_vehicle is NULL.
    I'm not sure what it should achieve, maybe you should replace this join with an EXISTS sub select, maybe you can remove this join completely.
    Try to find an example where your query gives a different result than this one. And explain me why the result is different.
    select vh.id_vehicle,
          vh.id_customer,
          vd.model,
          vd.registration_number
    from Insurance-Customers-Vehicles vh
    inner join Vehicles vd on (vh.cod_vehiculo = vd.cod_vehiculo)
    where vh.id_customer = 123456
    and vh.id_vehicle is null;Message was edited by:
    Sven W.

  • Slow query times with "contains" and "or"

    We're running Oracle 9.2.0.4 on RHEL 3
    I have a simple table - "docinfo". I've create a multicolumn Text index for docinfo called "repoidx". I have five cases below with the fourth one being the most difficult to understand. I have a primary key for "docinfo" but do nott have any additional indexes on "docinfo" right now because we're still testing the design. I'm curious about what is magical about using "or" plus "contains" in the same query (case 4).
    [case 1 - simple like]
    select count(docid)
    from sa.docinfo
    where
    author like '%smith%'
    Elapsed: 00:00:00.02
    Execution Plan
    0 SELECT STATEMENT Optimizer=ALL_ROWS (Cost=1468 Card=1 Bytes=15)
    1 0 SORT (AGGREGATE)
    2 1 TABLE ACCESS (FULL) OF 'DOCINFO' (Cost=1468 Card=12004 Bytes=180060)
    [case 2 - simple contains]
    select count(docid)
    from sa.docinfo
    where contains(repoidx,'facts')>0
    Elapsed: 00:00:01.00
    Execution Plan
    0 SELECT STATEMENT Optimizer=ALL_ROWS (Cost=3905 Card=1 Bytes=12)
    1 0 SORT (AGGREGATE)
    2 1 TABLE ACCESS (BY INDEX ROWID) OF 'DOCINFO' (Cost=3905 Card=21278 Bytes=255336)
    3 2 DOMAIN INDEX OF 'IDX_DOCINFO_REPOIDX' (Cost=3549)
    [case 3 - simple like _and_ simple contains]
    select count(docid)
    from sa.docinfo
    where
    contains(repoidx,'facts')>0
    and
    author like '%smith%'
    Elapsed: 00:00:00.02
    Execution Plan
    0 SELECT STATEMENT Optimizer=ALL_ROWS (Cost=3905 Card=1 Bytes= 23)
    1 0 SORT (AGGREGATE)
    2 1 TABLE ACCESS (BY INDEX ROWID) OF 'DOCINFO' (Cost=3905 Card=1064 Bytes=24472)
    3 2 DOMAIN INDEX OF 'IDX_DOCINFO_REPOIDX' (Cost=3549)
    [case 4 - simple like _or_ simple contains]
    select count(docid)
    from sa.docinfo
    where
    contains(repoidx,'facts')>0
    or
    author like '%smith%'
    Elapsed: 00:01:37.02
    Execution Plan
    0 SELECT STATEMENT Optimizer=ALL_ROWS (Cost=1468 Card=1 Bytes= 23)
    1 0 SORT (AGGREGATE)
    2 1 TABLE ACCESS (FULL) OF 'DOCINFO' (Cost=1468 Card=32218 Bytes=741014)
    [case 5 - simple like union simple contains]
    select count(docid)
    from sa.docinfo
    where
    contains(repoidx,'facts')>0
    union
    select count(docid)
    from sa.docinfo
    where
    author like '%smith%'
    Elapsed: 00:00:00.04
    Execution Plan
    0 SELECT STATEMENT Optimizer=ALL_ROWS (Cost=5581 Card=2 Bytes= 27)
    1 0 SORT (UNIQUE) (Cost=5581 Card=2 Bytes=27)
    2 1 UNION-ALL
    3 2 SORT (AGGREGATE) (Cost=4021 Card=1 Bytes=12)
    4 3 TABLE ACCESS (BY INDEX ROWID) OF 'DOCINFO' (Cost=3905 Card=21278 Bytes=255336)
    5 4 DOMAIN INDEX OF 'IDX_DOCINFO_REPOIDX' (Cost=3549)
    6 2 SORT (AGGREGATE) (Cost=1560 Card=1 Bytes=15)
    7 6 TABLE ACCESS (FULL) OF 'DOCINFO' (Cost=1468 Card=12004 Bytes=180060)

    Case 1:
    There is no index on author and it would not be able to use one if there was, due to the leading %, so it does a full table scan, which is still quick, since that is all there is to the query.
    Case 2:
    It has an index on repoidx, so it uses it and it is quick.
    Case 3:
    It has an index on repoidx, so it uses it. Since "and" is used, both conditions must be met. It has quckly obtained the results that match the first condition using the index, so it only has to check those rows, not every row in the table, to see if they also match the second condition.
    Case 4:
    Either condition may be met. It does not have an index on author, so it cannot use an index for that conditiion. Either condition can be met and it cannot duplicate the rows where both conditions are met, so it cannot use the results of one condition to check the other. So, it has to do a full table scan, in order to check every row for either condition, so it is slow.
    Case 5:
    select count (docid)
    from   docinfo
    where  contains (repoidx, 'facts') > 0
    union
    select count (docid)
    from   docinfo
    where  author like '%smith%';is not the same as:
    select count (docid)
    from   (select docid
            from   docinfo
            where  contains (repoidx, 'facts') > 0
            union
            select docid
            from   docinfo
            where  author like '%smith%');which is the same as case 4 and therefore just as slow. Your case 5 is just taking the union of 2 numbers, which could result in one row or two rows, depending on whether the numbers happen to match or not. Consider the following:
    scott@ORA92> SELECT job, empno
      2  FROM   emp
      3  /
    JOB            EMPNO
    CLERK           7369
    SALESMAN        7499
    SALESMAN        7521
    MANAGER         7566
    SALESMAN        7654
    MANAGER         7698
    MANAGER         7782
    ANALYST         7788
    PRESIDENT       7839
    SALESMAN        7844
    CLERK           7876
    CLERK           7900
    ANALYST         7902
    CLERK           7934
    14 rows selected.
    scott@ORA92> SELECT job, COUNT (empno)
      2  FROM   emp
      3  GROUP  BY job
      4  /
    JOB       COUNT(EMPNO)
    ANALYST              2
    CLERK                4
    MANAGER              3
    PRESIDENT            1
    SALESMAN             4
    scott@ORA92> SELECT COUNT (empno)
      2  FROM   emp
      3  WHERE  job = 'SALESMAN'
      4  /
    COUNT(EMPNO)
               4
    scott@ORA92> SELECT COUNT (empno)
      2  FROM   emp
      3  WHERE  job = 'CLERK'
      4  /
    COUNT(EMPNO)
               4
    scott@ORA92> SELECT COUNT (empno)
      2  FROM   emp
      3  WHERE  job = 'SALESMAN'
      4  UNION
      5  SELECT COUNT (empno)
      6  FROM   emp
      7  WHERE  job = 'CLERK'
      8  /
    COUNT(EMPNO)
               4
    scott@ORA92> -- the above is the same as:
    scott@ORA92> SELECT 4 FROM DUAL
      2  UNION
      3  SELECT 4 FROM DUAL
      4  /
             4
             4
    scott@ORA92> -- it is not the same as:
    scott@ORA92> SELECT COUNT (empno)
      2  FROM   (SELECT empno
      3            FROM   emp
      4            WHERE  job = 'SALESMAN'
      5            UNION
      6            SELECT empno
      7            FROM   emp
      8            WHERE  job = 'CLERK')
      9  /
    COUNT(EMPNO)
               8
    scott@ORA92> -- if the numbers are different, you get 2 rows:
    scott@ORA92> SELECT COUNT (empno)
      2  FROM   emp
      3  WHERE  job = 'ANALYST'
      4  UNION
      5  SELECT COUNT (empno)
      6  FROM   emp
      7  WHERE  job = 'MANAGER'
      8  /
    COUNT(EMPNO)
               2
               3
    scott@ORA92> -- the above is the same as:
    scott@ORA92> SELECT 2 FROM DUAL
      2  UNION
      3  SELECT 3 FROM DUAL
      4  /
             2
             2
             3
    scott@ORA92> -- it is not the same as:
    scott@ORA92> SELECT COUNT (empno)
      2  FROM   (SELECT empno
      3            FROM   emp
      4            WHERE  job = 'ANALYST'
      5            UNION
      6            SELECT empno
      7            FROM   emp
      8            WHERE  job = 'MANAGER')
      9  /
    COUNT(EMPNO)
               5

  • Select with transposition and join

    Hi Guys!
    I'm using Oracle 9i and I'm facing the following problem:
    My table looks like this:
    Stripe
    Unit
    Value
    1
    1
    a1
    1
    2
    a2
    1
    3
    a3
    2
    1
    b1
    2
    2
    b2
    2
    3
    b3
    2
    4
    b4
    4
    1
    c1
    4
    2
    c2
    4
    3
    c3
    4
    4
    c4
    4
    5
    c5
    My result should look like this:
    Unit
    Stripe1 Value
    Stripe2 Value
    Stripe3 Value
    Stripe4 Value
    1
    a1
    b1
    c1
    2
    a2
    b2
    c2
    3
    a3
    b3
    c3
    4
    b4
    c4
    5
    c5
    I tried it with one select for each stripe and full joins, but in this example I would only see the first 3 units....
    Any ideas?

    Another way, but only if your on database version 11gR1 and onwards, is to use the PIVOT operator:
    SQL> -- generating sample date:
    SQL> with t as (
      2  select 1 stripe, 1 unit, 'a1' value from dual union
      3  select 1, 2, 'a2' from dual union
      4  select 1, 3, 'a3' from dual union
      5  select 2, 1, 'b1' from dual union
      6  select 2, 2, 'b2' from dual union
      7  select 2, 3, 'b3' from dual union
      8  select 2, 4, 'b4' from dual union
      9  select 4, 1, 'c1' from dual union
    10  select 4, 2, 'c2' from dual union
    11  select 4, 3, 'c3' from dual union
    12  select 4, 4, 'c4' from dual union
    13  select 4, 5, 'c5' from dual
    14  )
    15  --
    16  -- actual query:
    17  --
    18  select *
    19  from ( select unit
    20         ,      stripe
    21         ,      value
    22         from   t
    23       )
    24  pivot (max(value) for (stripe) in ( 1 as stripe1value
    25                                    , 2 as stripe2value
    26                                    , 3 as stripe3value
    27                                    , 4 as stripe4value
    28                                    )
    29        )
    30  order by unit;
          UNIT ST ST ST ST
             1 a1 b1    c1
             2 a2 b2    c2
             3 a3 b3    c3
             4    b4    c4
             5          c5
    5 rows selected.
    ORACLE-BASE - PIVOT and UNPIVOT Operators in Oracle Database 11g Release 1

  • UPDATE Statement with subquerry and join

    I have 2 tables (say, employee and dept). employee.empno and dept.empno.
    These tables are not joined.
    I want to update the first name (fname) in employee WHERE employee.empno = dept.empno
    My query is :
    UPDATE emp SET fname='jack' WHERE exists(select * from emp,dept where emp.empno = dept.empno)
    But this query updates all the records.... even where there is no corresponding record in dept
    For example, emp has empno values of 10,20,30,40 and dept has empno values of 10 and 20 only,
    yet all records in emp are updated.
    Can someone help me ???
    null

    That is because an UPDATE statemente without a WHERE clause will update all of the rows.
    There are three parts to an UPDATE
    UPDATE tablename
    SET columnlist
    WHERE
    The UPDATE clause specifies the table to update.
    The SET clause specifies the columns to update and the values to use to update them.
    The WHERE clause specified which records in the table to update.
    No WHERE clause means update all rows.
    The correlated subquery in the SET clause has nothing to do with the WHERE clause that determines which rows get updated. You have to be very careful to also include a WHERE clause (that often duplicates the WHERE clause in the subquery) or you will set columns to NULL that don't get values returned from the subquery.
    Alias the emp table being updated and do not include the emp table in the subquery.
    Also I suggest you use 'X' (or any constant that is not actually in the table) in the EXISTS test.
    UPDATE emp e SET fname='jack' WHERE exists(select 'x' from dept where e.empno = dept.empno)
    WHERE exists (select 'x' from dept where e.empno = dept.empno

  • Slow Query time with Function in Group By

    I have a PL/SQL function that computes status based on several inputs. When the function is run in a standard query without a group by, it is very fast. When i try to count or sum other columns in the select (thus requiring the Group By), my query response time explodes exponentially.
    My query:
    SELECT
    ben.atm_class( 'DBT', 'CLA' , 6 , 1245 ),
    count (distinct ax.HOUSEHOLD_KEY)
    FROM
    ADM.PRODUCT p,
    ADM.ACCOUNT_CROSS_FUNCTIONAL ax
    WHERE
    ax.month_key = 1245
    AND ( ax.PRODUCT_KEY=ADM.P.PRODUCT_KEY )
    AND ( ax.HOUSEHOLD_KEY ) IN (6)
    group by
    p.ptype, p.stype,
    ben.atm_class( 'DBT', 'CLA' , 6 , 1245 )
    My explain plan for the query with the Group By:
    Operation     Object Name     Rows     Bytes     Cost     Object Node     In/Out     PStart     PStop
    SELECT STATEMENT Optimizer Mode=CHOOSE          3           10                     
    SORT GROUP BY          3      60      10                     
    NESTED LOOPS          3      60      6                     
    TABLE ACCESS BY LOCAL INDEX ROWID     ACCOUNT_CROSS_FUNCTIONAL     3      33      3                23     23
    INDEX RANGE SCAN     NXIF312ACCOUNT_CROSS_FUNCTION     3           2                23     23
    TABLE ACCESS BY INDEX ROWID     PRODUCT     867      7 K     1                     
    INDEX UNIQUE SCAN     PK_PRODUCT_PRODUCTKEY     867                               
    This executes in over 9 minutes.
    My query w/o Group by
    SELECT
    ben.atm_class( 'DBT', 'CLA' , 6 , 1245 ),
    ax.HOUSEHOLD_KEY
    FROM
    ADM.PRODUCT p,
    ADM.ACCOUNT_CROSS_FUNCTIONAL ax
    WHERE
    ax.month_key = 1245
    AND ( ax.PRODUCT_KEY=ADM.P.PRODUCT_KEY )
    AND ( ax.HOUSEHOLD_KEY ) IN (6)
    My explain plan without the Group By:
    Operation     Object Name     Rows     Bytes     Cost     Object Node     In/Out     PStart     PStop
    SELECT STATEMENT Optimizer Mode=CHOOSE          3           3                     
    NESTED LOOPS          3      42      3                     
    TABLE ACCESS BY LOCAL INDEX ROWID     ACCOUNT_CROSS_FUNCTIONAL     3      33      3                23     23
    INDEX RANGE SCAN     NXIF312ACCOUNT_CROSS_FUNCTION     3           2                23     23
    INDEX UNIQUE SCAN     PK_PRODUCT_PRODUCTKEY     867      2 K                         
    This executes in 6 seconds
    Any thoughts on why it takes 90 times longer to perform the Group By sort?

    The plan didn't paste:
    no group by:
    Operation     Object Name     Rows     Bytes     Cost     Object Node     In/Out     PStart     PStop
    SELECT STATEMENT Optimizer Mode=CHOOSE          3           6                     
    NESTED LOOPS          3      60      6                     
    TABLE ACCESS BY LOCAL INDEX ROWID     ACCOUNT_CROSS_FUNCTIONAL     3      33      3                23     23
    INDEX RANGE SCAN     NXIF312ACCOUNT_CROSS_FUNCTION     3           2                23     23
    TABLE ACCESS BY INDEX ROWID     PRODUCT     867      7 K     1                     
    INDEX UNIQUE SCAN     PK_PRODUCT_PRODUCTKEY     867                               
    group by:
    Operation     Object Name     Rows     Bytes     Cost     Object Node     In/Out     PStart     PStop
    SELECT STATEMENT Optimizer Mode=CHOOSE          3           10                     
    SORT GROUP BY          3      60      10                     
    NESTED LOOPS          3      60      6                     
    TABLE ACCESS BY LOCAL INDEX ROWID     ACCOUNT_CROSS_FUNCTIONAL     3      33      3                23     23
    INDEX RANGE SCAN     NXIF312ACCOUNT_CROSS_FUNCTION     3           2                23     23
    TABLE ACCESS BY INDEX ROWID     PRODUCT     867      7 K     1                     
    INDEX UNIQUE SCAN     PK_PRODUCT_PRODUCTKEY     867                               

  • Error in UPDATE statement with SET and JOIN

    Hi
    UPDATE lms_assessment_student QS JOIN lms_assessment_student_ans QA ON QS.pk_Assessment_Stud_Id = QA.fk_Assessment_Stud_Id SET QA.Mark = 1, QA.Comment_Field = 1 WHERE QS.pk_Assessment_Stud_Id = 1 AND QA.Question_Id = 1;
    The above statement when executing is showing ORA-00971: missing SET keyword. so i changed it to
    UPDATE lms_assessment_student QS SET QA.Mark = 1, QA.Comment_Field = 1 WHERE QS.pk_Assessment_Stud_Id = 1 AND QA.Question_Id = 1 JOIN lms_assessment_student_ans QA ON QS.pk_Assessment_Stud_Id = QA.fk_Assessment_Stud_Id ;
    and it showing ORA-00933: SQL command not properly ended.So can anyone help me in solving this problem
    Thanking you in advance
    Dinny

    Hi ,
    So many errors
    YOUR QUERY :
    UPDATE lms_assessment_student QS SET QA.Mark = 1, QA.Comment_Field = 1 WHERE QS.pk_Assessment_Stud_Id = 1 AND QA.Question_Id = 1 JOIN lms_assessment_student_ans QA ON QS.pk_Assessment_Stud_Id = QA.fk_Assessment_Stud_Id ;
    and it showing ORA-00933: SQL command not properly ended.So can anyone help me in solving this problem
    first thing u want to update qa and u write update QS ??
    Second y do u want to join??? just put the condition
    SOLUTION
    UPDATE lms_assessment_student_ans
    SET lms_assessment_student_ans.Mark = 1,
    lms_assessment_student_ans.Comment_Field = 1
    WHERE lms_assessment_student.pk_Assessment_Stud_Id = 1
    AND lms_assessment_student.pk_Assessment_Stud_Id = QA.fk_Assessment_Stud_Id
    Hope it works for u..
    Bhavesh

  • Where clause with XMLExists and join on another table

    Hi,
    We have table like:
    drop table xml_tbl;
    create table xml_tbl (
    xml_msg_id integer,
    xml_msg_text xmltype
    insert into xml_tbl values
    (1, '<main><id>1</id></main>') ;
    insert into xml_tbl values --(xml_msg_id,xml_msg_text)
    (1, '<main><id>2</id></main>') ;
    Another table like:
    create Table Table1
    ( id1 int);
    Insert into Table1 values(2);
    Insert into Table1 values(3);
    We need to have a view on top of the table xml_tbl where /main/id should have only those values which are in id1 column of table Table1.
    Something like
    CREATE OR REPLACE VIEW V_xml_tbl
    xml_msg_text
    AS
    SELECT T.xml_msg_text
    FROM xml_tbl T
    WHERE XMLEXISTS (
    'declare namespace Namesp1 ="Abc:Set";
    let $Results as xs:boolean := fn:exists($p/main/id in (Select id1 from Table1)) --Now here I know I can't do Select id1 from
    Table1*
    return if ($Results ) then true() else ()'
    PASSING T.xml_msg_text AS "p");
    Actually in the real scenario Table1 will have many IDs and xml_tbl has many XML files..
    So I am stuck on how to do it. Please help.
    Thanks..
    Edited by: user8941550 on Nov 20, 2012 7:19 PM

    One of these two :
    SQL> select t.xml_msg_text
      2  from xml_tbl t
      3  where exists (
      4    select null
      5    from table1 t1
      6    where t1.id1 = xmlcast(
      7                     xmlquery('/main/id' passing t.xml_msg_text returning content)
      8                     as integer
      9                   )
    10  );
    XML_MSG_TEXT
    <main>
      <id>2</id>
    </main>
    SQL> select t.xml_msg_text
      2  from xml_tbl t
      3     , xmltable('/main' passing t.xml_msg_text
      4         columns id integer path 'id'
      5       ) x
      6  where exists (
      7    select null
      8    from table1 t1
      9    where t1.id1 = x.id
    10  );
    XML_MSG_TEXT
    <main>
      <id>2</id>
    </main>
    And a third one, using XMLExists :
    SQL> select t.xml_msg_text
      2  from xml_tbl t
      3  where xmlexists (
      4    'fn:collection("oradb:/DEV/TABLE1")/ROW[ID1=$d/main/id]'
      5    passing t.xml_msg_text as "d"
      6  );
    XML_MSG_TEXT
    <main>
      <id>2</id>
    </main>
    Execution Plan
    Plan hash value: 3633580934
    | Id  | Operation           | Name    | Rows  | Bytes | Cost (%CPU)| Time     |
    |   0 | SELECT STATEMENT    |         |     2 |   116 |     8   (0)| 00:00:01 |
    |*  1 |  FILTER             |         |       |       |            |          |
    |   2 |   TABLE ACCESS FULL | XML_TBL |     2 |   116 |     3   (0)| 00:00:01 |
    |   3 |   NESTED LOOPS      |         |     1 |     5 |     5   (0)| 00:00:01 |
    |   4 |    TABLE ACCESS FULL| TABLE1  |     2 |     6 |     3   (0)| 00:00:01 |
    |*  5 |    XPATH EVALUATION |         |       |       |            |          |
    Predicate Information (identified by operation id):
       1 - filter( EXISTS (SELECT 0 FROM "DEV"."TABLE1"
                  "SYS_ORAVW_2",XPATHTABLE('/main/id' PASSING :B1 COLUMNS "C_00$" XMLTYPE
                  PATH '.', "C_01$" XQEXVAL CHAR PATH '.')  "P" WHERE
                  TO_BINARY_DOUBLE("ID1")=TO_BINARY_DOUBLE("P"."C_01$")))
       5 - filter(TO_BINARY_DOUBLE("ID1")=TO_BINARY_DOUBLE("P"."C_01$"))The plan is similar to that of the second query above (XMLTable/EXISTS).
    Still using XMLExists, a plan similar to the first query (EXISTS/XMLCast/XMLQuery) can be achieved by casting id to an integer datatype :
    SQL> select t.xml_msg_text
      2  from xml_tbl t
      3  where xmlexists (
      4    'fn:collection("oradb:/DEV/TABLE1")/ROW[ID1=xs:int($d/main/id)]'
      5    passing t.xml_msg_text as "d"
      6  );
    XML_MSG_TEXT
    <main>
      <id>2</id>
    </main>
    Execution Plan
    Plan hash value: 1149640166
    | Id  | Operation          | Name    | Rows  | Bytes | Cost (%CPU)| Time     |
    |   0 | SELECT STATEMENT   |         |     1 |    61 |     7  (15)| 00:00:01 |
    |*  1 |  HASH JOIN SEMI    |         |     1 |    61 |     7  (15)| 00:00:01 |
    |   2 |   TABLE ACCESS FULL| XML_TBL |     2 |   116 |     3   (0)| 00:00:01 |
    |   3 |   TABLE ACCESS FULL| TABLE1  |     2 |     6 |     3   (0)| 00:00:01 |
    Predicate Information (identified by operation id):
       1 - access("ID1"=SYS_XQ_ATOMCNVCHK(TO_NUMBER(SYS_XQ_UPKXML2SQL(SYS_XQ
                  EXVAL(SYS_XQEXTRACT(SYS_MAKEXML(0,"T"."SYS_NC00003$"),'/main/id'),1,50,3
                  3792,8192),50,1,0)),2,37))
    Note
       - Unoptimized XML construct detected (enable XMLOptimizationCheck for more information)Check each one on your real scenario to see which show best performance.
    (I would tend to say the ones involving streaming evaluation)
    Edited by: odie_63 on 5 nov. 2012 12:24
    Edited by: odie_63 on 5 nov. 2012 12:38

  • SQL QUERY TUNING(PARTITONS AND JOIN)

    Hello
    My below query is taking very long time to execute ..here is the query and explain plan
    EXPLAIN PLAN FOR select w.ref_no,a.*
    from table1 a left outer join table2 w
    on(a.emp_id=w.emp_id)
    where a.joining_date=20090205 ;
    PLAN_TABLE_OUTPUT
    | Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Pstart| Pstop |
    | 0 | SELECT STATEMENT | | 2415K| 504M| | 226K (2)| | |
    |* 1 | HASH JOIN OUTER | | 2415K| 504M| 488M| 226K (2)| | |
    |* 2 | TABLE ACCESS BY INDEX ROWID| table1 | 2415K| 460M| | 77975 (1)| | |
    |* 3 | INDEX RANGE SCAN | table1_joining_ DATE | 2441K| | | 6463 (2)| | |
    | 4 | PARTITION RANGE ALL | | 39M | 718M| | 64745 (2)| 1 | 4 |
    | 5 | TABLE ACCESS FULL | table2 | 39M | 718M| | 64745 (2)| 1 | 4 |
    table 2 has 40 million rows
    Table2 structure
    emp_id
    ref_no
    Project_id
    Partitoned on Project_id, Project_id is nowhere used on the above query
    Table1 Structure
    emp_id
    joining_date
    other columns
    Is indexed on joining_date, not partitioned
    Please advise

    The CBO has estimated that you have 2415K table1 rows where joining_date = 20090205. (By the way: is this really a number?!)
    Is this estimate accurate?
    Please add some more information:
    - Which version do you use
    - How long is "very long time"?
    - How many does your query return
    - information as described in this thread: When your query takes too long ...
    Regards,
    Rob.

  • Very Slow Query with CTE inner join

    I have 2 tables (heavily simplified here to show relevant columns):
    CREATE TABLE tblCharge
    (ChargeID int NOT NULL,
    ParentChargeID int NULL,
    ChargeName varchar(200) NULL)
    CREATE TABLE tblChargeShare
    (ChargeShareID int NOT NULL,
    ChargeID int NOT NULL,
    TotalAmount money NOT NULL,
    TaxAmount money NULL,
    DiscountAmount money NULL,
    CustomerID int NOT NULL,
    ChargeShareStatusID int NOT NULL)
    I have a very basic View to Join them:
    CREATE VIEW vwBASEChargeShareRelation as
    Select c.ChargeID, ParentChargeID, s.CustomerID, s.TotalAmount, isnull(s.TaxAmount, 0) as TaxAmount, isnull(s.DiscountAmount, 0) as DiscountAmount
    from tblCharge c inner join tblChargeShare s
    on c.ChargeID = s.ChargeID Where s.ChargeShareStatusID < 3
    GO
    I then have a view containing a CTE to get the children of the Parent Charge:
    ALTER VIEW [vwChargeShareSubCharges] AS
    WITH RCTE AS
    SELECT ParentChargeId, ChargeID, 1 AS Lvl, ISNULL(TotalAmount, 0) as TotalAmount, ISNULL(TaxAmount, 0) as TaxAmount,
    ISNULL(DiscountAmount, 0) as DiscountAmount, CustomerID, ChargeID as MasterChargeID
    FROM vwBASEChargeShareRelation Where ParentChargeID is NULL
    UNION ALL
    SELECT rh.ParentChargeID, rh.ChargeID, Lvl+1 AS Lvl, ISNULL(rh.TotalAmount, 0), ISNULL(rh.TaxAmount, 0), ISNULL(rh.DiscountAmount, 0) , rh.CustomerID
    , rc.MasterChargeID
    FROM vwBASEChargeShareRelation rh
    INNER JOIN RCTE rc ON rh.PArentChargeID = rc.ChargeID and rh.CustomerID = rc.CustomerID
    Select MasterChargeID as ChargeID, CustomerID, Sum(TotalAmount) as TotalCharged, Sum(TaxAmount) as TotalTax, Sum(DiscountAmount) as TotalDiscount
    from RCTE
    Group by MasterChargeID, CustomerID
    GO
    So far so good, I can query this view and get the total cost for a line item including all children.
    The problem occurs when I join this table. The query:
    Select t.* from vwChargeShareSubCharges t
    inner join
    tblChargeShare s
    on t.CustomerID = s.CustomerID
    and t.MasterChargeID = s.ChargeID
    Where s.ChargeID = 1291094
    Takes around 30 ms to return a result (tblCharge and Charge Share have around 3.5 million records).
    But the query:
    Select t.* from vwChargeShareSubCharges t
    inner join
    tblChargeShare s
    on t.CustomerID = s.CustomerID
    and t.MasterChargeID = s.ChargeID
    Where InvoiceID = 1045854
    Takes around 2 minutes to return a result - even though the only charge with that InvoiceID is the same charge as the one used in the previous query.
    The same thing occurs if I do the join in the same query that the CTE is defined in.
    I ran the execution plan for each query. The first (fast) query looks like this:
    The second(slow) query looks like this:
    I am at a loss, and my skills at decoding execution plans to resolve this are lacking.
    I have separate indexes on tblCharge.ChargeID, tblCharge.ParentChargeID, tblChargeShare.ChargeID, tblChargeShare.InvoiceID, tblChargeShare.ChargeShareStatusID
    Any ideas? Tested on SQL 2008R2 and SQL 2012

    >> The database is linked [sic] to an established app and the column and table names can't be changed. <<
    Link? That is a term from pointer chains and network databases, not SQL. I will guess that means the app came back in the old pre-RDBMS days and you are screwed. 
    >> I am not too worried about the money field [sic], this is used for money and money based calculations so the precision and rounding are acceptable at this level. <<
    Field is a COBOL concept; columns are totally different. MONEY is how Sybase mimics the PICTURE clause that puts currency signs, commas, period, etc in a COBOL money field. 
    Using more than one operation (multiplication or division) on money columns will produce severe rounding errors. A simple way to visualize money arithmetic is to place a ROUND() function calls after 
    every operation. For example,
    Amount = (Portion / total_amt) * gross_amt
    can be rewritten using money arithmetic as:
    Amount = ROUND(ROUND(Portion/total_amt, 4) * 
    gross_amt, 4)
    Rounding to four decimal places might not seem an 
    issue, until the numbers you are using are greater 
    than 10,000. 
    BEGIN
    DECLARE @gross_amt MONEY,
     @total_amt MONEY,
     @my_part MONEY,
     @money_result MONEY,
     @float_result FLOAT,
     @all_floats FLOAT;
     SET @gross_amt = 55294.72;
     SET @total_amt = 7328.75;
     SET @my_part = 1793.33;
     SET @money_result = (@my_part / @total_amt) * 
    @gross_amt;
     SET @float_result = (@my_part / @total_amt) * 
    @gross_amt;
     SET @Retult3 = (CAST(@my_part AS FLOAT)
     / CAST( @total_amt AS FLOAT))
     * CAST(FLOAT, @gross_amt AS FLOAT);
     SELECT @money_result, @float_result, @all_floats;
    END;
    @money_result = 13525.09 -- incorrect
    @float_result = 13525.0885 -- incorrect
    @all_floats = 13530.5038673171 -- correct, with a -
    5.42 error 
    >> The keys are ChargeID(int, identity) and ChargeShareID(int, identity). <<
    Sorry, but IDENTITY is not relational and cannot be a key by definition. But it sure works just like a record number in your old COBOL file system. 
    >> .. these need to be int so that they are assigned by the database and unique. <<
    No, the data type of a key is not determined by physical storage, but by logical design. IDENTITY is the number of a parking space in a garage; a VIN is how you identify the automobile. 
    >> What would you recommend I use as keys? <<
    I do not know. I have no specs and without that, I cannot pull a Kabbalah number from the hardware. Your magic numbers can identify Squids, Automobile or Lady Gaga! I would ask the accounting department how they identify a charge. 
    >> Charge_Share_Status_ID links [sic] to another table which contains the name, formatting [sic] and other information [sic] or a charge share's status, so it is both an Id and a status. <<
    More pointer chains! Formatting? Unh? In RDBMS, we use a tiered architecture. That means display formatting is in a presentation layer. A properly created table has cohesion – it does one and only one data element. A status is a state of being that applies
    to an entity over a period time (think employment, marriage, etc. status if that is too abstract). 
    An identifier is based on the Law of Identity from formal logic “To be is to be something in particular” or “A is A” informally. There is no entity here! The Charge_Share_Status table should have the encoded values for a status and perhaps a description if
    they are unclear. If the list of values is clear, short and static, then use a CHECK() constraint. 
    On a scale from 1 to 10, what color is your favorite letter of the alphabet? Yes, this is literally that silly and wrong. 
    >> I understand what a CTE is; is there a better way to sum all children for a parent hierarchy? <<
    There are many ways to represent a tree or hierarchy in SQL.  This is called an adjacency list model and it looks like this:
    CREATE TABLE OrgChart 
    (emp_name CHAR(10) NOT NULL PRIMARY KEY, 
     boss_emp_name CHAR(10) REFERENCES OrgChart(emp_name), 
     salary_amt DECIMAL(6,2) DEFAULT 100.00 NOT NULL,
     << horrible cycle constraints >>);
    OrgChart 
    emp_name  boss_emp_name  salary_amt 
    ==============================
    'Albert'    NULL    1000.00
    'Bert'    'Albert'   900.00
    'Chuck'   'Albert'   900.00
    'Donna'   'Chuck'    800.00
    'Eddie'   'Chuck'    700.00
    'Fred'    'Chuck'    600.00
    This approach will wind up with really ugly code -- CTEs hiding recursive procedures, horrible cycle prevention code, etc.  The root of your problem is not knowing that rows are not records, that SQL uses sets and trying to fake pointer chains with some
    vague, magical non-relational "id".  
    This matches the way we did it in old file systems with pointer chains.  Non-RDBMS programmers are comfortable with it because it looks familiar -- it looks like records and not rows.  
    Another way of representing trees is to show them as nested sets. 
    Since SQL is a set oriented language, this is a better model than the usual adjacency list approach you see in most text books. Let us define a simple OrgChart table like this.
    CREATE TABLE OrgChart 
    (emp_name CHAR(10) NOT NULL PRIMARY KEY, 
     lft INTEGER NOT NULL UNIQUE CHECK (lft > 0), 
     rgt INTEGER NOT NULL UNIQUE CHECK (rgt > 1),
      CONSTRAINT order_okay CHECK (lft < rgt));
    OrgChart 
    emp_name         lft rgt 
    ======================
    'Albert'      1   12 
    'Bert'        2    3 
    'Chuck'       4   11 
    'Donna'       5    6 
    'Eddie'       7    8 
    'Fred'        9   10 
    The (lft, rgt) pairs are like tags in a mark-up language, or parens in algebra, BEGIN-END blocks in Algol-family programming languages, etc. -- they bracket a sub-set.  This is a set-oriented approach to trees in a set-oriented language. 
    The organizational chart would look like this as a directed graph:
                Albert (1, 12)
        Bert (2, 3)    Chuck (4, 11)
                       /    |   \
                     /      |     \
                   /        |       \
                 /          |         \
            Donna (5, 6) Eddie (7, 8) Fred (9, 10)
    The adjacency list table is denormalized in several ways. We are modeling both the Personnel and the Organizational chart in one table. But for the sake of saving space, pretend that the names are job titles and that we have another table which describes the
    Personnel that hold those positions.
    Another problem with the adjacency list model is that the boss_emp_name and employee columns are the same kind of thing (i.e. identifiers of personnel), and therefore should be shown in only one column in a normalized table.  To prove that this is not
    normalized, assume that "Chuck" changes his name to "Charles"; you have to change his name in both columns and several places. The defining characteristic of a normalized table is that you have one fact, one place, one time.
    The final problem is that the adjacency list model does not model subordination. Authority flows downhill in a hierarchy, but If I fire Chuck, I disconnect all of his subordinates from Albert. There are situations (i.e. water pipes) where this is true, but
    that is not the expected situation in this case.
    To show a tree as nested sets, replace the nodes with ovals, and then nest subordinate ovals inside each other. The root will be the largest oval and will contain every other node.  The leaf nodes will be the innermost ovals with nothing else inside them
    and the nesting will show the hierarchical relationship. The (lft, rgt) columns (I cannot use the reserved words LEFT and RIGHT in SQL) are what show the nesting. This is like XML, HTML or parentheses. 
    At this point, the boss_emp_name column is both redundant and denormalized, so it can be dropped. Also, note that the tree structure can be kept in one table and all the information about a node can be put in a second table and they can be joined on employee
    number for queries.
    To convert the graph into a nested sets model think of a little worm crawling along the tree. The worm starts at the top, the root, makes a complete trip around the tree. When he comes to a node, he puts a number in the cell on the side that he is visiting
    and increments his counter.  Each node will get two numbers, one of the right side and one for the left. Computer Science majors will recognize this as a modified preorder tree traversal algorithm. Finally, drop the unneeded OrgChart.boss_emp_name column
    which used to represent the edges of a graph.
    This has some predictable results that we can use for building queries.  The root is always (left = 1, right = 2 * (SELECT COUNT(*) FROM TreeTable)); leaf nodes always have (left + 1 = right); subtrees are defined by the BETWEEN predicate; etc. Here are
    two common queries which can be used to build others:
    1. An employee and all their Supervisors, no matter how deep the tree.
     SELECT O2.*
       FROM OrgChart AS O1, OrgChart AS O2
      WHERE O1.lft BETWEEN O2.lft AND O2.rgt
        AND O1.emp_name = :in_emp_name;
    2. The employee and all their subordinates. There is a nice symmetry here.
     SELECT O1.*
       FROM OrgChart AS O1, OrgChart AS O2
      WHERE O1.lft BETWEEN O2.lft AND O2.rgt
        AND O2.emp_name = :in_emp_name;
    3. Add a GROUP BY and aggregate functions to these basic queries and you have hierarchical reports. For example, the total salaries which each employee controls:
     SELECT O2.emp_name, SUM(S1.salary_amt)
       FROM OrgChart AS O1, OrgChart AS O2,
            Salaries AS S1
      WHERE O1.lft BETWEEN O2.lft AND O2.rgt
        AND S1.emp_name = O2.emp_name 
       GROUP BY O2.emp_name;
    4. To find the level and the size of the subtree rooted at each emp_name, so you can print the tree as an indented listing. 
    SELECT O1.emp_name, 
       SUM(CASE WHEN O2.lft BETWEEN O1.lft AND O1.rgt 
       THEN O2.sale_amt ELSE 0.00 END) AS sale_amt_tot,
       SUM(CASE WHEN O2.lft BETWEEN O1.lft AND O1.rgt 
       THEN 1 ELSE 0 END) AS subtree_size,
       SUM(CASE WHEN O1.lft BETWEEN O2.lft AND O2.rgt
       THEN 1 ELSE 0 END) AS lvl
      FROM OrgChart AS O1, OrgChart AS O2
     GROUP BY O1.emp_name;
    5. The nested set model has an implied ordering of siblings which the adjacency list model does not. To insert a new node, G1, under part G.  We can insert one node at a time like this:
    BEGIN ATOMIC
    DECLARE rightmost_spread INTEGER;
    SET rightmost_spread 
        = (SELECT rgt 
             FROM Frammis 
            WHERE part = 'G');
    UPDATE Frammis
       SET lft = CASE WHEN lft > rightmost_spread
                      THEN lft + 2
                      ELSE lft END,
           rgt = CASE WHEN rgt >= rightmost_spread
                      THEN rgt + 2
                      ELSE rgt END
     WHERE rgt >= rightmost_spread;
     INSERT INTO Frammis (part, lft, rgt)
     VALUES ('G1', rightmost_spread, (rightmost_spread + 1));
     COMMIT WORK;
    END;
    The idea is to spread the (lft, rgt) numbers after the youngest child of the parent, G in this case, over by two to make room for the new addition, G1.  This procedure will add the new node to the rightmost child position, which helps to preserve the idea
    of an age order among the siblings.
    6. To convert a nested sets model into an adjacency list model:
    SELECT B.emp_name AS boss_emp_name, E.emp_name
      FROM OrgChart AS E
           LEFT OUTER JOIN
           OrgChart AS B
           ON B.lft
              = (SELECT MAX(lft)
                   FROM OrgChart AS S
                  WHERE E.lft > S.lft
                    AND E.lft < S.rgt);
    7. To find the immediate parent of a node: 
    SELECT MAX(P2.lft), MIN(P2.rgt)
      FROM Personnel AS P1, Personnel AS P2
     WHERE P1.lft BETWEEN P2.lft AND P2.rgt 
       AND P1.emp_name = @my_emp_name;
    I have a book on TREES & HIERARCHIES IN SQL which you can get at Amazon.com right now. It has a lot of other programming idioms for nested sets, like levels, structural comparisons, re-arrangement procedures, etc. 
    --CELKO-- Books in Celko Series for Morgan-Kaufmann Publishing: Analytics and OLAP in SQL / Data and Databases: Concepts in Practice Data / Measurements and Standards in SQL SQL for Smarties / SQL Programming Style / SQL Puzzles and Answers / Thinking
    in Sets / Trees and Hierarchies in SQL

  • Sql query slowness due to rank and columns with null values:

        
    Sql query slowness due to rank and columns with null values:
    I have the following table in database with around 10 millions records:
    Declaration:
    create table PropertyOwners (
    [Key] int not null primary key,
    PropertyKey int not null,    
    BoughtDate DateTime,    
    OwnerKey int null,    
    GroupKey int null   
    go
    [Key] is primary key and combination of PropertyKey, BoughtDate, OwnerKey and GroupKey is unique.
    With the following index:
    CREATE NONCLUSTERED INDEX [IX_PropertyOwners] ON [dbo].[PropertyOwners]    
    [PropertyKey] ASC,   
    [BoughtDate] DESC,   
    [OwnerKey] DESC,   
    [GroupKey] DESC   
    go
    Description of the case:
    For single BoughtDate one property can belong to multiple owners or single group, for single record there can either be OwnerKey or GroupKey but not both so one of them will be null for each record. I am trying to retrieve the data from the table using
    following query for the OwnerKey. If there are same property rows for owners and group at the same time than the rows having OwnerKey with be preferred, that is why I am using "OwnerKey desc" in Rank function.
    declare @ownerKey int = 40000   
    select PropertyKey, BoughtDate, OwnerKey, GroupKey   
    from (    
    select PropertyKey, BoughtDate, OwnerKey, GroupKey,       
    RANK() over (partition by PropertyKey order by BoughtDate desc, OwnerKey desc, GroupKey desc) as [Rank]   
    from PropertyOwners   
    ) as result   
    where result.[Rank]=1 and result.[OwnerKey]=@ownerKey
    It is taking 2-3 seconds to get the records which is too slow, similar time it is taking as I try to get the records using the GroupKey. But when I tried to get the records for the PropertyKey with the same query, it is executing in 10 milliseconds.
    May be the slowness is due to as OwnerKey/GroupKey in the table  can be null and sql server in unable to index it. I have also tried to use the Indexed view to pre ranked them but I can't use it in my query as Rank function is not supported in indexed
    view.
    Please note this table is updated once a day and using Sql Server 2008 R2. Any help will be greatly appreciated.

    create table #result (PropertyKey int not null, BoughtDate datetime, OwnerKey int null, GroupKey int null, [Rank] int not null)Create index idx ON #result(OwnerKey ,rnk)
    insert into #result(PropertyKey, BoughtDate, OwnerKey, GroupKey, [Rank])
    select PropertyKey, BoughtDate, OwnerKey, GroupKey,
    RANK() over (partition by PropertyKey order by BoughtDate desc, OwnerKey desc, GroupKey desc) as [Rank]
    from PropertyOwners
    go
    declare @ownerKey int = 1
    select PropertyKey, BoughtDate, OwnerKey, GroupKey
    from #result as result
    where result.[Rank]=1
    and result.[OwnerKey]=@ownerKey
    go
    Best Regards,Uri Dimant SQL Server MVP,
    http://sqlblog.com/blogs/uri_dimant/
    MS SQL optimization: MS SQL Development and Optimization
    MS SQL Consulting:
    Large scale of database and data cleansing
    Remote DBA Services:
    Improves MS SQL Database Performance
    SQL Server Integration Services:
    Business Intelligence

  • Set READ UNCOMMITED for a query with a table join (Ver 12.5. and 15.5)

    Hi all,
    this is an example of how to set the READ UNCOMMITED isolation level for a simple query:
    select col_a from mytable at isolation 0
    What about a query with an equi-join?
    Is it:
    select col_a
    from mytable t1, mytable t2
    at isolation 0
    I am sorry for the simple question, I did not find a auitable example in the documentation.
    Best Regards
    Arthur

    Yeah, the docs aren't very good at providing a robust set of examples so you've gotta:
    1 - review the command syntax and then
    2 - try a few examples until you find the format that works
    1 - From the ASE 15.5 Commands reference manual we find the following syntax:
    =========================
    select ::=
              select [all | distinct]
              [top unsigned_integer]
              select_list
              [into_clause]
              [from_clause]
              [where_clause]
              [group_by_clause]
              [having_clause]
              [order_by_clause]
              [compute_clause]
              [read_only_clause]
              [isolation_clause]
              [browse_clause]
              [plan_clause]
    =========================
    This shows us that the isolation clause is attached at the 'end' of the query as a query-level specifier (along with the 'group by', 'order by' and 'having' clauses).
    From this syntax I'd say your proposed query looks correct so ...
    2 - Try running your example to see if you get a syntax error ("When in doubt, try it out!"), eg:
    =========================
    select s.name,c.name
    from sysobjects s, syscolumns c
    where s.id = c.id
    at isolation 0
    go
    name
    sysobjects
    sysobjects
    sysobjects
    ... snip ...
    =========================

  • Hierarchical connect by and start with and joins?

    I've got an employees table and an identifiers table. The identifiers table is hierarchical, with parents and children. Each employee has one or more identifiers, but only one identifier is considered the "primary" or root identifier for each employee. Unfortunately, the employee table might be pointing at one of the child identifier rows and not the root. I need a fast query to join the employees with their most current (root) identifier.
    Here's code to define the problem.
    create table employees (employeeid varchar2(8), fakeNationalID varchar2(9), empname varchar2(30));
    insert into employees (employeeid, fakeNationalID, empname) values (1,'001000001','John Smith');
    insert into employees (employeeid, fakeNationalID, empname) values (2,'002000002','James Jones');
    create table realids (realidkey NUMBER, fakeNationalID VARCHAR2(9) not null,
       realNationalID VARCHAR2(9) UNIQUE, parent_realidkey number);
    insert into realids (realidkey, fakeNationalID, realNationalID, parent_realidkey) values
       (1,'001000001','111111111',3);
    insert into realids (realidkey, fakeNationalID, realNationalID, parent_realidkey) values
       (2,'002000002','222222222',null);
    insert into realids (realidkey, fakeNationalID, realNationalID, parent_realidkey) values
       (3,'003000003','333333333',null);
    commit;  
    create or replace function get_parentid (fakeID in VARCHAR2) return varchar2 is
       tempid VARCHAR2(9);
       begin
          select realNationalID into tempid
             from (
               select realNationalID, fakeNationalID
                  from realids
                  start with fakeNationalID = fakeID
                  connect by nocycle prior parent_realidkey = realidkey
                  order by level desc)
                  where rownum = 1;
          return tempid;
          exception
             when NO_DATA_FOUND then
                return NULL;
             when others then raise;
        end;
    select get_parentid('001000001') from dual; -- returns 333333333 because its linked to a parent
    select get_parentid('002000002') from dual; -- returns 222222222 because there is only one child
    select get_parentid('003000003') from dual; -- returns 333333333 because it is the parentWhat I want is to get the highest parent node in realids for each row in employees...
    This works, but is NOT very efficient:
    select employeeid, get_parentid(fakeNationalID) realid, empname from employees;
    employeeid   realid       empname
    1            333333333     John Smith
    2            222222222     James JonesYou can imagine what this would be like with 100K rows or greater. It takes about 3 minutes to run.
    This seemed like a good way to do this, but with a sub query.
    select e.employeeid, e.fakenationalid, e.empname, sub.realnationalid
       from employees,
          (select realidkey, fakenationalid, realnationalid, parent_realidkey
             from realids r
             start with r.fakenationalid = e.fakenationalid
             connect by prior r.parent_realidkey = r.realidkey) subUnfortunately, it produces an invalid identifier on e.fakenationalid (in the start with clause).
    Anyone have any ideas on how to get the top most parent node from the realids for each row in the employees table? In real life there are 6 or more employees tables spread across several remote instances some of which point at children in the realids table and some of which point at the parents. We always want the top most parent realid. Any help would be much appreciated.

    Hi,
    Thanks for posting the sample data in such a convenient form!
    It always helps to post your Oracle version, too, especially when dealing with CONNECT BY queries.
    The following does what you requested in Oracle 10:
    WITH     got_roots   AS
         SELECT     CONNECT_BY_ROOT     fakenationalid     AS leaf_id
         ,     realnationalid
         FROM     realids
         WHERE     CONNECT_BY_ISLEAF     = 1
         START WITH      fakenationalid IN ( SELECT  fakenationalid
                                              FROM    employees
         CONNECT BY     realidKEY     = PRIOR parent_realidkey
    SELECT     e.employeeid
    ,     r.realnationalid
    ,     e.empname
    FROM     employees     e
    JOIN     got_roots     r     ON     r.leaf_id     = e.fakenationalid
    ;In any query, calling a user-defined function for each row is going to be slow. Fortunately, Oracle now has built-in functions and operators that can take the place of get_parentid. The CONNECT_BY_ROOT operator, which was introduced in Oracle 10, is the key to this problem. In Oracle 9, you can get the same results using SYS_CONNECT_BY_PATH.
    It's usually faster to do the CONNECT BY query separately, and then join whatever other tables you need to the results.
    You had a good idea in your last query. The problem was that sub and employees were equal tables in the FROM clause, and you can't correlate equals. You can only correlate a sub-query to its super-query. You could make that general idea work by changing sub into a scalar sub-query,which could be correlated to employees, but I think it would be a lot less efficient than what I posted above.

  • Doughts on Infoset Joins with Cube and DSO in BI 7

    Dear All,
    I have a droughts on Infoset Joints.
    I am working on a BI Query where I need to take 0Employee from Cube and Employee position time he holds in an Organization is coming form DSO, Apart for this I also have other requirement such as Address fields , Visa Status , are all coming from DSO.
    I have created a Infoset for this where
    1st is Cube and its 0Employee is linked to all DSO Employee and also Employee position I have linked with DSO and all are inner joints.
    1>My doughty is that will this work with inner joins or I have to use other joints.
    2>Is sequence of Data Target is correct
    which is
    1> Cube and in 2> all DSO in Parallel.
    Please guide me on joints and sequence.
    Thanks V V much in Advance,
    Regards,

    Hi,
    Check these links.
    http://help.sap.com/saphelp_nw04s/helpdata/en/ed/084e3ce0f9fe3fe10000000a114084/frameset.htm
    https://www.sdn.sap.com/irj/sdn/go/portal/prtroot/docs/library/uuid/2f5aa43f-0c01-0010-a990-9641d3d4eef7
    http://help.sap.com/saphelp_nw04/helpdata/en/9c/6b7538c9a8ee45e10000009b38f8cf/frameset.htm
    if this helpa assign points.
    Thanks.....
    Vasu.....

  • Query with FULL OUTER JOIN , help pleaseeeeeeeeeeee...

    Hi everyone,
    I'm trying to write a query for a report in Oracle SQL, but i just can't figure out how to do it.
    I'm using Oracle 10g release 1.0 database and i execute my queris in SQL* PLUS ( eventually i'm gonna use them in Oracle Report Builder ) .
    here's what i have:
    i have four tables that are used for our inventory application. lets call them INCOMMING , INCOMMING_ITEMS , OUTGOING , OUTGOING_ITEMS.
    as you may have guessed , INCOMMING_ITEMS is the detail table for INCOMMING ( joined by IID column) and also OUTGOING_ITEMS is the detail table for OUTGOING ( joined by OID column ).
    here is the structure of them :
    INCOMMING
    IID varchar2
    CDATE date
    INCOMMING_ITEM
    IID varchar2
    PART_NO number
    QTY number
    OUTGOING
    OID varchar2
    CDATE date
    OUTGOING_ITEM
    OID varchar2
    PART_NO number
    QTY number
    now , the query i want, should return part_no , cdate , sum of OUTGOING qty , sum of INCOMMING qty .
    the result of the query should be sth like this :
    part_no     cdate     O_qty     I_qty
    100     01/05/06     10     0
    100     01/05/07     20     60
    200     01/06/02     0     50
    300     01/06/02     30     40
    this means that for some dates and for some parts, i may not have INCOMMING or OUTGOING data, but if at least one of the 2 last columns has a non-zero data, i should show the row ( like the first and third rows of my example result), and if both have data for the same PART_NO and the same CDATE, both should be showed in the same row. ( like the second row in my example result)
    i tried so much and came up with several huge and also time consuming queries, but then i read abt FULL OUTER JOIN somewhere and tried using that. here is what i came up with :
    SELECT
    PART_NO , CDATE , sum(II.QTY) I_QTY , SUM (OI.QTY) O_QTY
    FROM
         (OUTGOING O INNER JOIN OUTGOING_ITEM OI USING ( OID ) )
    FULL OUTER JOIN
         (INCOMMING I INNER JOIN INCOMMING_ITEM II USING ( IID ) )
    ON ( I.CDATE = O.CDATE AND II.PART_NO = OI.PART_NO)
    WHERE
    I.CDATE = :PARAMETER1
    AND O.CDATE = :PARAMETER1
    GROUP BY
    PART_NO , CDATE
    this query is short and fast , but the results r not what i expected. i mean, although i have used FULL OUTER JOIN in the query , but the results i get r sth like this :
    part_no     cdate     O_qty     I_qty
    100     01/05/07     20     60
    300     01/06/02     30     40
    which means only the rows that has both values are returned.
    any change i make to this query would make the SQL* PLUS hang , like when i use the cartesian product of two large tables, so i guess my changes wheren't in the right direction.
    i think its possible to write this query using FULL OUTER JOIN syntax, but i just can't find it.
    Can anybody pleaseeeeeeeeeeeee help me?
    thanx in advance,
    Maryam.

    Note: I wrote this on the fly -- hope there is no syntax errors, otherwise forgive me -- but you get the idea..
    select
    fromUnionAll.cdate, fromUnionAll.part_no,
    sum(fromUnionAll.O_qty) O_qty,
    sum(fromUnionAll.I_qty) I_qty
    from
    select
    iinner.cdate, iinner.part_no, 0 O_qty, iinner.I_qty
    from
    select
    i.cdate, ii.part_no,
    /* added the case only for the extreme case when there is
    no record anywhere for the given CDATE in INCOMMING_item */
    sum( ( case when ii.qty is not null then ii.qty else 0 end) ) I_qty
    from
    incomming i,
    incomming_item ii
    where
    i.iid = ii.iid (+)
    group by i.cdate, ii.part_no
    ) iinner
    union all
    select
    oinner.cdate, oinner.part_no, oinner.O_qty, 0 I_qty
    from
    select
    o.cdate, oi.part_no,
    /* added the case only for the extreme case when there is
    no record anywhere for the given CDATE in OUTGOING_item */
    sum( ( case when oi.qty is not null then oi.qty else 0 end) ) O_qty
    from
    outgoing o,
    outgoing_item oi
    where
    o.oid = oi.oid (+)
    group by o.cdate, oi.part_no
    ) oinner
    ) fromUnionAll
    group by fromUnionAll.cdate, fromUnionAll.part_no;
    --Samson                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       

  • Query with multiple outer joins

    I had a doubt with whether the following kind of query is valid with multiple outer-joins. The format of the query is something like this:-
    select A.col1, B.col2
    from table1 A, table2 B, table3 C where
    A.col3=B.col4(+) and B.col5=C.col6(+)
    This would mean the follwoing with regard to outer-joins in the query.
    1) fetch records with col3 in table A matching or not matching col4 in table B
    2) fetch records with col5 in table B matching or not matching col6 in table C
    So, this query is valid?
    I hope, my question is clear.
    Please, help in solving the doubt.
    regards

    This is valid and it works fine

Maybe you are looking for

  • Error during installation of photosmart b209a-m drivers on windows 8.1

    I recently acquired a new HP 110-120 desktop for one of my customers. Prior to delivery I wanted to install the printer software and drivers so that everything worked upon delivery. I downloaded the most recent drivers for windows 8.1 64 bit OS  (PS_

  • Issues with CS3 Licensing

    Hello, My CS3 programs have stopped working since I loaded them back on from a time machine backup. Upon opening any of the programs, the following dialog appears: I have tried uninstalling and reinstalling from the discs, but cannot get past this. 

  • Network Error - Sync Using LAN with TCPIP 100mbps

    Hi im facing an unknown issue while sync. 1. Using a gprs line i can sync the db (Fairly a large db 400mb) But when use the LAN it says Network Disconnected during async -Check for network Active. username/password and server url are correctly entere

  • Airport Extreme and WD My Book World Edition

    Hello, I am considering buying an airport extreme, but I am fairly new to the product and had some questions about it. I have a WD My Book World Edition wireless hard drive, is it possible to plug the hard drive into the airport extreme via ethernet

  • Why won't iTunes start?

    I bought a PowerMac G5 and it came with OS X 10.5.8 pre-installed. I used that for a while till I got my hands on a retail Leopard disc. I wiped the HDD and did a clean install, and now iTunes won't start. It says there's not enough memory available,