Having clause not working - sql

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

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.

Related

SQL Math Operation In Correlated Subquery

I am working with three tables, basically, one is a bill of materials, one contains part inventory, and the last one contains work orders or jobs. I am trying to find out if it is possible to have a correlated subquery that can perform a math operation using a value from the outer query. Here's an example of what I'm trying to do:
SELECT A.work_order,A.assembly,A.job_quantity,
(SELECT COUNT(X.part_number)
FROM bom X
WHERE X.assembly = A.assembly
AND (X.quantity_required * A.job_quantity) >= (SELECT Y.quantity_available FROM inventory Y WHERE
Y.part_number = X.part_number)) AS negatives
FROM work_orders A
ORDER BY A.assembly ASC
I am attempting to find out, for a given work order, if there are parts that we do not have enough of to build the assembly. I'm currently getting an "Error correlating fields" error. Is it possible to do this kind of operation in a single query?
Try moving the subquery to a join, something like this:
SELECT a.work_order, a.assembly, a.job_quantity, n.negatives
FROM work_orders a JOIN (SELECT x.part_number, COUNT(x.part_number) as negatives
FROM bom x JOIN work_orders b
ON x.assembly = b.assembly
WHERE (x.quantity_required * b.job_quantity) >= (SELECT y.quantity_available
FROM inventory y WHERE
y.part_number = x.part_number)
GROUP BY x.part_number) n
ON a.part_number = n.part_number
ORDER BY a.assembly ASC
Or create a temporary cursor with the subquery and then use it to join the main table.
Hope this helps.
Luis

COUNT is outputting more than one row

I am having a problem with my SQL query using the count function.
When I don't have an inner join, it counts 55 rows. When I add the inner join into my query, it adds a lot to it. It suddenly became 102 rows.
Here is my SQL Query:
SELECT COUNT([fmsStage].[dbo].[File].[FILENUMBER])
FROM [fmsStage].[dbo].[File]
INNER JOIN [fmsStage].[dbo].[Container]
ON [fmsStage].[dbo].[File].[FILENUMBER] = [fmsStage].[dbo].[Container].[FILENUMBER]
WHERE [fmsStage].[dbo].[File].[RELATIONCODE] = 'SHIP02'
AND [fmsStage].[dbo].[Container].DELIVERYDATE BETWEEN '2016-10-06' AND '2016-10-08'
GROUP BY [fmsStage].[dbo].[File].[FILENUMBER]
Also, I have to do TOP 1 at the SELECT statement because it returns 51 rows with random numbers inside of them. (They are probably not random, but I can't figure out what they are.)
What do I have to do to make it just count the rows from [fmsStage].[dbo].[file].[FILENUMBER]?
First, your query would be much clearer like this:
SELECT COUNT(f.[FILENUMBER])
FROM [fmsStage].[dbo].[File] f INNER JOIN
[fmsStage].[dbo].[Container] c
ON v.[FILENUMBER] = c.[FILENUMBER]
WHERE f.[RELATIONCODE] = 'SHIP02' AND
c.DELIVERYDATE BETWEEN '2016-10-06' AND '2016-10-08';
No GROUP BY is necessary. Otherwise you'll just one row per file number, which doesn't seem as useful as the overall count.
Note: You might want COUNT(DISTINCT f.[FILENUMBER]). Your question doesn't provide enough information to make a judgement.
Just remove GROUP BY Clause
SELECT COUNT([fmsStage].[dbo].[File].[FILENUMBER])
FROM [fmsStage].[dbo].[File]
INNER JOIN [fmsStage].[dbo].[Container]
ON [fmsStage].[dbo].[File].[FILENUMBER] = [fmsStage].[dbo].[Container].[FILENUMBER]
WHERE [fmsStage].[dbo].[File].[RELATIONCODE] = 'SHIP02'
AND [fmsStage].[dbo].[Container].DELIVERYDATE BETWEEN '2016-10-06' AND '2016-10-08'

The "where" condition worked not as expected ("or" issue)

I have a problem to join thoses 4 tables
Model of my database
I want to count the number of reservations with different sorts (user [mrbs_users.id], room [mrbs_room.room_id], area [mrbs_area.area_id]).
Howewer when I execute this query (for the user (id=1) )
SELECT count(*)
FROM mrbs_users JOIN mrbs_entry ON mrbs_users.name=mrbs_entry.create_by
JOIN mrbs_room ON mrbs_entry.room_id = mrbs_room.id
JOIN mrbs_area ON mrbs_room.area_id = mrbs_area.id
WHERE mrbs_entry.start_time BETWEEN "145811700" and "1463985000"
or
mrbs_entry.end_time BETWEEN "1458120600" and "1463992200" and mrbs_users.id = 1
The result is the total number of reservations of every user, not just the user who has the id = 1.
So if anyone could help me.. Thanks in advance.
Use parentheses in the where clause whenever you have more than one condition. Your where is parsed as:
WHERE (mrbs_entry.start_time BETWEEN "145811700" and "1463985000" ) or
(mrbs_entry.end_time BETWEEN "1458120600" and "1463992200" and
mrbs_users.id = 1
)
Presumably, you intend:
WHERE (mrbs_entry.start_time BETWEEN 145811700 and 1463985000 or
mrbs_entry.end_time BETWEEN 1458120600 and 1463992200
) and
mrbs_users.id = 1
Also, I removed the quotes around the string constants. It is bad practice to mix data types, and in some databases, the conversion between types can make the query less efficient.
The problem you've faced caused by the incorrect condition WHERE.
So, should be:
WHERE (mrbs_entry.start_time BETWEEN 145811700 AND 1463985000 )
OR
(mrbs_entry.end_time BETWEEN 1458120600 AND 1463992200 AND mrbs_users.id = 1)
Moreover, when you use only INNER JOIN (JOIN) then it be better to avoid WHERE clause, because the ON clause is executed before the WHERE clause, so criteria there would perform faster.
Your query in this case should be like this:
SELECT COUNT(*)
FROM mrbs_users
JOIN mrbs_entry ON mrbs_users.name=mrbs_entry.create_by
JOIN mrbs_room ON mrbs_entry.room_id = mrbs_room.id
AND
(mrbs_entry.start_time BETWEEN 145811700 AND 1463985000
OR ( mrbs_entry.end_time BETWEEN 1458120600 AND 1463992200 AND mrbs_users.id = 1)
)
JOIN mrbs_area ON mrbs_room.area_id = mrbs_area.id

SQL COUNT FORM JOIN TABLES

I have the following sql command:
SELECT "USERNAME"."TOPICS".VALUE,
"USERNAME"."TOPICS".QID,
"USERNAME"."QUESTION".QRATING
FROM "USERNAME"."TOPICS" JOIN "USERNAME"."QUESTION"
ON "USERNAME"."TOPICS".QID = "USERNAME"."QUESTION".QID
AND "USERNAME"."TOPICS".VALUE = 'kia'
ORDER BY QRATING DESC
It works really well, but I want to count how many element returns. So I tried to use:
SELECT COUNT("USERNAME"."TOPICS".QID)
FROM "USERNAME"."TOPICS" JOIN "USERNAME"."QUESTION"
ON "USERNAME"."TOPICS".QID = "USERNAME"."QUESTION".QID
AND "USERNAME"."TOPICS".VALUE = 'kia'
ORDER BY QRATING DESC
But I get the error :
Column reference 'USERNAME.TOPICS.VALUE' is invalid. When the SELECT
list contains at least one aggregate then all entries must be valid
aggregate expressions.
What is the problem?
Hmmm. The ORDER BY should be getting the error, not the SELECT. However, your query would be much easier to understand using table aliases:
SELECT COUNT(t.QID)
FROM "USERNAME"."TOPICS" t JOIN
"USERNAME"."QUESTION" q
ON t.QID = q.QID AND t.VALUE = 'kia';
If the first query works, I see no reason why this would not (and your original without the ORDER BY should also work).

SQl Query get data very slow from different tables

I am writing a sql query to get data from different tables but it is getting data from different tables very slowly.
Approximately above 2 minutes to complete.
What i am doing is here :
1. I am getting data differences and on behalf of date difference i am getting account numbers
2. I am comparing tables to get exact data i need.
here is my query
select T.accountno,
MAX(T.datetxn) as MxDt,
datediff(MM,MAX(T.datetxn), '2011-6-30') as Diffs,
max(P.Name) as POName
from Account_skd A,
AccountTxn_skd T,
POName P
where A.AccountNo = T.AccountNo and
GPOCode = A.OfficeCode and
Code = A.POCode and
A.servicecode = T.ServiceCode
group by T.AccountNo
order by len(T.AccountNo) DESC
please help that how i can use joins or any other way to get data within very less time say 5-10 seconds.
Since it appears you are getting EVERY ACCOUNT, and performance is slow, I would try by creating a prequery by just account, then do a single join to the other join tables something like..
select
T.Accountno,
T.MxDt,
datediff(MM, T.MxDt, '2011-6-30') as Diffs,
P.Name as POName
from
( select T1.AccountNo,
Max( T1.DateTxn ) MxDt
from AccontTxn_skd T1
group by T1.AccountNo ) T
JOIN Account_skd A
on T.AccountNo = A.AccountNo
JOIN POName P
on A.POCode = P.Code <-- GUESSING as you didn't qualify alias.field
AND A.OfficeCode = P.GPOCode <-- in your query for these two fields
order by
len(T.AccountNo) DESC
You had other elements based on the T.ServiceCode matching, but since you are only grouping on the account number anyhow, did it matter which service code was used? Otherwise, you would need to group by both the account AND service code (which I would have added the service code into the prequery and added as join condition to the account table too).