why does this query not give me only the specified accounts? - sql

Oracle SQL Developer
I expect to see:
In the subquery, I have that the rownumber be less than 2. When I run this query separately, it gives me 2 accounts. However, when I'm running the entire query, the list of account numbers just goes on! what's happening here?
SELECT m.acctno, i.intervalstartdate, d.name, i.intervalvalue
FROM endpoints E
JOIN meters m on m.acctid = e.acctid
LEFT JOIN intervaldata I ON I.acctid = M.acctid
LEFT JOIN endpointmodels EM ON EM.endpointmodelid=E.hwmodelid
LEFT JOIN datadefinitions D ON D.datadefinitionid = I.datadefinitionid
WHERE 1=1
AND E.statuscodeid = 8
AND m.FORM = 2
and exists
(
SELECT m2.acctno
from acct m2
where m2.acctno is not null
--and m2.acctno=m2.acctno
and rownum <= 2
)
AND D.datadefinitionid =7077
AND I.intervalstartdate BETWEEN '24-SEP-2017 00:00' and '25-SEP-2017 00:00'
--TRUNC(sysdate - 1) + interval '1' hour AND TRUNC(sysdate - 1) + interval
'24' hour
ORDER BY M.acctno, I.intervalstartdate, I.datadefinitionid
This query is supposed to give me 97 rows for each account. The data i'm reading, the interval values, are the data we report for each customer in 96 intervals. so Im expecting for 2 accounts for example, to get 194 rows. i want to test for 2 accounts now, but then i want to run for 50,000. so with 2, it's not even working. Just giving me millions of rows for two accounts. Basicaly, i think my row num line of code is being ignored. I can't use an in clause because i cant pass 50,000 accounts into there. so I used the exist operator.
Let me know!

I think the error is in trying to use and exists (...) clause. The exists predicate returns true if the subquery returns any rows at all. So, in your case, the result of exists will always be true, unless the table is empty. This means it has no effect whatsoever on the outer query. You need to use something like
inner join (SELECT m2.acctno
from acct m2
where m2.acctno is not null
--and m2.acctno=m2.acctno
and rownum <= 2) sub1
on sub1.acctno = m.acctno
to get what you want instead of and exists (...).

One obvious mistake is the date condition, where you require a date to be between two STRINGS. If you keep dates in string format, you will run into thousands of problems and bugs and you won't be able to fix them.
Do you understand that '25-APR-2008 00:00:00' is between '24-SEP-2017 00:00:00' and '25-SEP-2017 00:00:00', if you compare them alphabetically (as strings)?
The solution is to make sure the date column is in DATE (or TIMESTAMP) data type, and then to compare to dates, not to strings.
As an aside - this will not cause any errors, but it is still bad code - in the EXISTS condition you have a condition for ROWNUM <= 2. What do you think that will do? The subquery either returns at least one row (the first one will automatically have ROWNUM = 1) or it doesn't. The condition on ROWNUM in that subquery in the EXISTS condition is just garbage.

Related

Standard SQL - Work around needed for less than operator not working with blank/NULL date - AthenaS3

Goal: Join multiple attributes using PKs and then add multiple rows with unique Ids; d.activity_date, d.activity_type_id using ON d.lead_id AND d.activity_date between a.effective_start_date, a.effective_end_date.
This will give me a table I can use to pivot and view activity by a specific a.journey_id.
Current Outcome: When I add in the my second AND clause of less than a.effective_end_date the returned results set is missing rows due to NULL values in a.effective_end_date. Which makes sense...but now how do I quickly solve for it without a UNION? (Or maybe a UNION is the best option)
Expected Results: All rows of data where d.activity_date is equal to or between a.effective_start_date, a.effective_end_date and all rows where d.activity_date is greater than a.effective_start_date but a.effective_end_date is null.
This will increase row count and all d.attributes will be unique; Some a., b., c., attributes will duplicate.
SELECT
a.journey_id,
c.description,
a.customer_key_id,
b.lead_id,
a.is_active,
a.effective_start_date,
a.effective_end_date,
d.activity_date,
d.activity_type_id,
d.campaign_id,
d.primary_attribute_value_id,
d.primary_attribute_value,
d.attribute_values
FROM "data_lake"."journey_control" a
LEFT JOIN "data_lake"."mkto_leads" b
ON a.customer_key_id = b.customer_key_id
LEFT JOIN "data_lake"."journey" c
ON a.journey_id = c.journey_id
LEFT JOIN "data_lake"."mkto_activities" d
ON b.lead_id=d.lead_id
WHERE a.customer_key_id = 'XXXX-954b-46c3-92c8-5b47f50af988'
--This is where it breaks
What I've Tried:
AND d.activity_date >= a.effective_start_date --used alone returns all rows after start date (as expected)
AND d.activity_date <= a.effective_end_date --When I add this clause I get no results for all scenarios where a.effective_end_date is blank due to there being no data yet. (As expected)
--If I add AND a.effective_end_date IS NULL I lose my between results (As expected)
--AND d.activity_date BETWEEN a.effective_start_date AND a.effective_end_date - Works but again leaves out rows with no end date
Also Tried: Separate queries with a UNION - WORKS
--Looking for something more elegant.

Update table with combined field from other tables

I have a table with actions that are being due in the future. I have a second table that holds all the cases, including the due date of the case. And I have a third table that holds numbers.
The problems is as follows. Our system automatically populates our table with future actions. For some clients however, we need to change these dates. I wanted to create an update query for this, and have this run through our scheduler. However, I am kind of stuck at the moment.
What I have on code so far is this:
UPDATE proxima_gestion p
SET fecha = (SELECT To_char(d.f_ult_vencim + c.hrem01, 'yyyyMMdd')
FROM deuda d,
c4u_activity_dates c,
proxima_gestion p
WHERE d.codigo_cliente = c.codigo_cliente
AND p.n_expediente = d.n_expediente
AND d.saldo > 1000
AND p.tipo_gestion_id = 914
AND p.codigo_oficina = 33
AND d.f_ult_vencim > sysdate)
WHERE EXISTS (SELECT *
FROM proxima_gestion p,
deuda d
WHERE p.n_expediente = d.n_expediente
AND d.saldo > 1000
AND p.tipo_gestion_id = 914
AND p.codigo_oficina = 33
AND d.f_ult_vencim > sysdate)
The field fecha is the current action date. Unfortunately, this is saved as a char instead of date. That is why I need to convert the date back to a char. F_ult_vencim is the due date, and hrem01 is the number of days the actions should be placed away from the due date. (for example, this could be 10, making the new date 10 days after the due date)
Apart from that, there are a few more criteria when we need to change the date (certain creditors, certain departments, only for future cases and starting from a certain amount, only for a certain action type.)
However, when I try and run this query, I get the error message
ORA-01427: single-row subquery returns more than one row
If I run both subqueries seperately, I get 2 results from both. What I am trying to accomplish, is that it connects these 2 queries, and updates the field to the new value. This value will be different for every case, as every due date will be different.
Is this even possible? And if so, how?
You're getting the error because the first SELECT is returning more than one row for each row in the table being updated.
The first thing I see is that the alias for the table in UPDATE is the same as the alias in both SELECTs (p). So all of the references to p in the subqueries are referencing proxima_gestion in the subquery rather than the outer query. That is, the subquery is not dependent on the outer query, which is required for an UPDATE.
Try removing "proxima_gestion p" from FROM in both subqueries. The references to p, then, will be to the outer UPDATE query.

oracle sql query generating some unexected resutls

I have an sql query in which I have table named attan for the attendance and column named
S_TIME in which I stored in time and out time with a setting a flag of in with I and for O
Now I am trying to get in time as well as out time using the flag. I have written a query but result from this query are making some wrong sense.
Here is my query
SELECT X.AC_NO, X.IN_TIME, Y.OUT_TIME, X.S_DTE, X.CHK_IN, Y.CHK_OUT
FROM (SELECT A.AC_NO, A.S_TIME IN_TIME, A.AC_CHECKTYPE CHK_IN, A.S_DTE
FROM ATTN A
WHERE A.AC_CHECKTYPE = 'I' AND A.S_DTE = :P_DTE) X,
(SELECT B.AC_NO, B.S_TIME OUT_TIME, B.AC_CHECKTYPE CHK_OUT
FROM ATTN B
WHERE B.AC_CHECKTYPE = 'O' AND B.S_DTE = :P_DTE) Y
WHERE X.AC_NO = Y.AC_NO(+)
Through this query I always get the number of records of the employees who are in and only get 2 number of reocrds with out time.
Whereas in table there are 234 number of emps who are in and 256 are out but results don't match the data.
Please any one help me if any problem in my query.
SUGGESTION:
Run the subselects and see if you're getting all the rows you expect, with and without the "A.S_DTE = :P_DTE" date filter:
SELECT A.AC_NO, A.S_TIME IN_TIME, A.AC_CHECKTYPE CHK_IN, A.S_DTE
FROM ATTN A
WHERE A.AC_CHECKTYPE = 'I' AND A.S_DTE = :P_DTE
My first guess is that maybe you have a datetime, and unless the hours/minutes/seconds match exactly, you won't get the row. You can use to_char() to have just the "date" portion in your "from":
http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:204714700346328550
In any case, seeing what rows you do (and don't) get in the subqueries should show you what's wrong with the complete query.
Please post back what you find!

SQL Left Outer Join doesn't give full table

I have searched for similar issues but I found nothing...
I have a problem with joining 2 tables in SQL. First table is created using following procedure
DECLARE #Sequence TABLE (n DATETIME NOT NULL)
DECLARE #Index INT
SET #Index = 1
WHILE #Index <= 96 BEGIN
INSERT #Sequence (n) VALUES (DATEADD(Minute, #Index * 5, DATEADD(Hour, -8, '06-25-2010 00:00:00')))
SET #Index = #Index + 1
END
And when I run a regular query like such:
SELECT
Sequence.n
FROM
#Sequence as Sequence
I get what I expect - 96 rows with DateTime values spaced by 5 minute intervals, ending 06-25-2010 00:00:00 (this value will later be substituted by parameter in SSRS Report, thats why it might look weird to specify 'end' of the range and use double DATEADD).
Now the second table contains values registered by PLMC controllers, and they also happen to register one record per 5 minutes (per pointID, but not to complicate it lets assume there is one PointID).
The problem is that sometimes the controller goes offline, and for a given point there is no value registered, not even a 0. Thats why if I want to get a full picture of last 8 hours from any given point I came up with this sequence table. So, if I take the values from the other table in the same time range using this query:
SELECT
DataTime, DataValue
FROM
PointValue
WHERE
PointValue.DataTime > DATEADD(Hour, -8, '06-22-2010 00:00:00')
AND PointValue.DataTime < '06-22-2010 00:00:00'
AND PointID = '5284'
I will get only 56 rows. This is because after 20:30 on that day the controller went offline and there are no records registered.
So here is the problem. I try to run this query to get one value for every 5 minutes, and hopefully still see the whole 96 rows (8 hours in 5min intervals) with null values after 20:30:
SELECT
Sequence.n,
PointValue.DataValue
FROM
#Sequence as Sequence LEFT OUTER JOIN PointValue
ON Sequence.n = PointValue.DataTime
WHERE
PointID = '5280'
Unforetunately the result is still 56 rows, with the same time stamps as the last query... I have tried every possible join and cannot get the Null values for the last 3,5h of the day. I'm sure I'm making a very simple mistake but I have tried different ways to solve it for hours now and I seriously need help.
SOLVED:
Thanks for your comments, I have started to modify the query after reading first comment to appear, by Blorgbeard. All I had to do is make a carthesian multiplication of my time sequence x all relevan pointIDs (since I don't need all), so as a result my 'FROM' looks as follows:
(SELECT Sequence.n, dbo.LABELS.theIndex FROM #TimeSequence as Sequence, dbo.LABELS
WHERE LEFT(dbo.LABELS.theLabel,2)='VA') as BaseTable
LEFT OUTER JOIN PointValue ON BaseTable.n = PointValue.DataTime AND BaseTable.theIndex = PointValue.PointID
Again, thank you for your help!
You need to move the PointID comparison into the ON clause - with it in the WHERE clause, you're forcing the LEFT JOIN to become an INNER JOIN:
ON Sequence.n = PointValue.DataTime AND
PointValue.PointID = '5280'
Conditions in the WHERE clause have to be met by every row in the result set.
I think the problem is:
WHERE
PointID = '5280'
Because PointID is in the PointValue table, so it will be null for missing rows, and null does not equal '5280'.
I think you could change it like this to make it work:
WHERE
(PointID is null) or (PointID = '5280')
This is because, in your NULL rows, PointID is not '5280'.
Try adding that to your JOIN clause...
ON Sequence.n = PointValue.DataTime AND PointID = '5280'

SQL Output Question

Edited
I am running into an error and I know what is happening but I can't see what is causing it. Below is the sql code I am using. Basically I am getting the general results I want, however I am not accurately giving the query the correct 'where' clause.
If this is of any assistance. The count is coming out as this:
Total Tier
1 High
2 Low
There are 4 records in the Enrollment table. 3 are active, and 1 is not. Only 2 of the records should be displayed. 1 for High, and 1 for low. The second Low record that is in the total was flagged as 'inactive' on 12/30/2010 and reflagged again on 1/12/2011 so it should not be in the results. I changed the initial '<=' to '=' and the results stayed the same.
I need to exclude any record from Enrollments_Status_Change that where the "active_status" was changed to 0 before the date.
SELECT COUNT(dbo.Enrollments.Customer_ID) AS Total,
dbo.Phone_Tier.Tier
FROM dbo.Phone_Tier as p
JOIN dbo.Enrollments as eON p.Phone_Model = e.Phone_Model
WHERE (e.Customer_ID NOT IN
(Select Customer_ID
From dbo.Enrollment_Status_Change as Status
Where (Change_Date >'12/31/2010')))
GROUP BY dbo.Phone_Tier.Tier
Thanks for any assistance and I apologize for any confusion. This is my first time here and i'm trying to correct my etiquette on the fly.
If you don't want any of the fields from that table dbo.Enrollment_Status_Change, and you don't seem to use it in any way — why even include it in the JOINs? Just leave it out.
Plus: start using table aliases. This is very hard to read if you use the full table name in each JOIN condition and WHERE clause.
Your code should be:
SELECT
COUNT(e.Customer_ID) AS Total, p.Tier
FROM
dbo.Phone_Tier p
INNER JOIN
dbo.Enrollments e ON p.Phone_Model = e.Phone_Model
WHERE
e.Active_Status = 1
AND EXISTS (SELECT DISTINCT Customer_ID
FROM dbo.Enrollment_Status_Change AS Status
WHERE (Change_Date <= '12/31/2010'))
GROUP BY
p.Tier
Also: most likely, your EXISTS check is wrong — since you didn't post your table structures, I can only guess — but my guess would be:
AND EXISTS (SELECT * FROM dbo.Enrollment_Status_Change
WHERE Change_Date <= '12/31/2010' AND CustomerID = e.CustomerID)
Check for existence of any entries in dbo.Enrollment_Status_Change for the customer defined by e.CustomerID, with a Change_Date before that cut-off date. Right?
Assuming you want to:
exclude all customers whose latest enrollment_status_change record was since the start of 2011
but
include all customers whose latest enrollment_status_change record was earlier than the end of 2010 (why else would you have put that EXISTS clause in?)
Then this should do it:
SELECT COUNT(e.Customer_ID) AS Total,
p.Tier
FROM dbo.Phone_Tier p
JOIN dbo.Enrollments e ON p.Phone_Model = e.Phone_Model
WHERE dbo.Enrollments.Active_Status = 1
AND e.Customer_ID NOT IN (
SELECT Customer_ID
FROM dbo.Enrollment_Status_Change status
WHERE (Change_Date >= '2011-01-01')
)
GROUP BY p.Tier
Basically, the problem with your code is that joining a one-to-many table will always increase the row count. If you wanted to exclude all the records that had a matching row in the other table this would be fine -- you could just use a LEFT JOIN and then set a WHERE clause like Customer_ID IS NULL.
But because you want to exclude a subset of the enrollment_status_change table, you must use a subquery.
Your intention is not clear from the example given, but if you wanted to exclude anyone who's enrollment_status_change as before 2011, but include those who's status change was since 2011, you'd just swap the date comparator for <.
Is this any help?