usman
usman

Reputation: 135

Having clause not working

i make this query in oracle 11g database

     SELECT   DISTINCT JOC_FIN_CLTH_DFCT_LOT.LOT_NO,
                    I.ISSUE_DATE,
                    R.PROC_DESC,
                    R.RECV_DATE,
                    M.DFCT_DATE,
                    JOC_FIN_CLTH_DFCT_LOT.FCD_MAIN_ID
    FROM   JOC_FIN_CLTH_DFCT_LOT,
           JOC_FIN_CLTH_DFCT_MAIN M,
           JOC_DAILY_FABRC_RECV_FOLD R,
           JOC_LOT_ISSUE_REG I
   WHERE       M.FCD_MAIN_ID = JOC_FIN_CLTH_DFCT_LOT.FCD_MAIN_ID
           AND R.LOT_NO = JOC_FIN_CLTH_DFCT_LOT.LOT_NO
           AND I.LOT_NO = R.LOT_NO
           AND I.LOT_YEAR = R.LOT_YEAR
           AND JOC_FIN_CLTH_DFCT_LOT.LOT_YEAR = R.LOT_YEAR
           AND JOC_FIN_CLTH_DFCT_LOT.LOT_YEAR = '1213'
           AND JOC_FIN_CLTH_DFCT_LOT.FCDL_ID IN
                    (    SELECT   MIN (DFCT_LOT.FCDL_ID)
    FROM   JOC_FIN_CLTH_DFCT_LOT DFCT_LOT, JOC_FIN_CLTH_DFCT_MAIN DFT_MAIN
   WHERE   DFCT_LOT.FCD_MAIN_ID IN (DFT_MAIN.FCD_MAIN_ID)
GROUP BY   DFCT_LOT.FCD_MAIN_ID)
ORDER BY   JOC_FIN_CLTH_DFCT_LOT.FCD_MAIN_ID

it retrieve data within 2 sec no. of rows=5100 but when i use this query in my front end application it takes too much times so after troubleshooting i find subquery cause problem when data retrieve so i simplify this query

  SELECT   DISTINCT DFCT_LOT.LOT_NO,
                    I.ISSUE_DATE,
                    R.PROC_DESC,
                    R.RECV_DATE,
                    M.DFCT_DATE,
                    DFCT_LOT.FCD_MAIN_ID
    FROM   JOC_FIN_CLTH_DFCT_LOT DFCT_LOT,
           JOC_FIN_CLTH_DFCT_MAIN M,
           JOC_DAILY_FABRC_RECV_FOLD R,
           JOC_LOT_ISSUE_REG I,
           JOC_FIN_CLTH_DFCT_MAIN DFT_MAIN
   WHERE       M.FCD_MAIN_ID = DFCT_LOT.FCD_MAIN_ID
           AND R.LOT_NO = DFCT_LOT.LOT_NO
           AND I.LOT_NO = R.LOT_NO
           AND I.LOT_YEAR = R.LOT_YEAR
           AND DFCT_LOT.LOT_YEAR = R.LOT_YEAR
           AND DFCT_LOT.LOT_YEAR = '1213'
           AND DFCT_LOT.FCD_MAIN_ID IN (DFT_MAIN.FCD_MAIN_ID)

GROUP BY   DFCT_LOT.FCDL_ID,
           DFCT_LOT.FCD_MAIN_ID,
           DFCT_LOT.LOT_NO,
           I.ISSUE_DATE,
           R.PROC_DESC,
           R.RECV_DATE,
           M.DFCT_DATE,
           DFCT_LOT.FCD_MAIN_ID
 HAVING   DFCT_LOT.FCDL_ID in MIN (DFCT_LOT.FCDL_ID)
ORDER BY   DFCT_LOT.FCD_MAIN_ID

this is simplified form of above query but number of rows increase no.of rows=5578 but i know the actual no. of rows=5100 having clause not working here kindly look into my query and guide me

Upvotes: 1

Views: 515

Answers (1)

trincot
trincot

Reputation: 350167

In your second query you are joining the table JOC_FIN_CLTH_DFCT_MAIN a second time, once as M and once as DFCT_LOT. In the second query's SELECT list you take the first column from M and the last one from DFCT_LOT.

But in the first query they are both from the same M table. When you have more than one record in JOC_FIN_CLTH_DFCT_MAIN for the same FCD_MAIN_ID, then this will result in more combinations in the second query, and this explains why you have more results with it.

But there are several other differences. In the second query you group by many more columns than in the first. Moreover, MIN (DFCT_LOT.FCDL_ID) does not really make sense in the second query, as it is already grouped by, so it is exactly the same as just DFCT_LOT.FCDL_ID. As a consequence, the HAVING clause is just a plain tautology, and you could just as well leave it out and still get the same results.

If you are sure the first query gives the results you want, then I would suggest a different way to achieve a possible optimisation of it:

SELECT      DISTINCT 
            L.LOT_NO,
            I.ISSUE_DATE,
            R.PROC_DESC,
            R.RECV_DATE,
            L.DFCT_DATE,
            L.FCD_MAIN_ID,
FROM        (SELECT     L.FCD_MAIN_ID,
                        L.LOT_NO,
                        L.LOT_YEAR,
                        M.DFCT_DATE,
                        ROW_NUMBER() OVER (PARTITION BY L.FCD_MAIN_ID 
                                           ORDER BY L.FCDL_ID) AS RN
            FROM        JOC_FIN_CLTH_DFCT_LOT   L, 
            INNER JOIN  JOC_FIN_CLTH_DFCT_MAIN  M
                    ON  M.FCD_MAIN_ID = L.FCD_MAIN_ID
            ) L
INNER JOIN  JOC_DAILY_FABRC_RECV_FOLD R
        ON  R.LOT_NO = L.LOT_NO
       AND  R.LOT_YEAR = L.LOT_YEAR
INNER JOIN  JOC_LOT_ISSUE_REG I
        ON  I.LOT_NO = R.LOT_NO
        AND I.LOT_YEAR = R.LOT_YEAR
WHERE       L.LOT_YEAR = '1213'
        AND L.RN = 1
ORDER BY    L.FCD_MAIN_ID

Note that I have used the ANSI/ISO syntax for joins, which I would strongly advise you to do. Defining join conditions in the WHERE clause is something of the eighties; don't do it. Queries becomes much more readable once you are used to the ANSI/ISO syntax.

The suggested query selects all the columns that are needed from both JOC_FIN_CLTH_DFCT_LOT and JOC_FIN_CLTH_DFCT_MAIN in the sub-query, that way you don't have to include those tables again.

The major trick is the use of the ROW_NUMBER window function, which gives an sequence number according to the PARTITION clause. The outer query then filters for only those records which got number 1, which are the records where the value of FCD_MAIN_ID is minimal for a given FCDL_ID.

Upvotes: 1

Related Questions