The Subquery which returns multiple rows in Oracle SQL - sql

I have a complex SQL query with multiple sub queries. The Query returns a very big data. The tables are dynamic and they get updated every day. Yesterday, the query didn't execute, because one of the subqueries returned multiple rows.
The subquery would be something like this.
Select Value1 from Table1 where Table1.ColumnName = 123456
Table1.ColumnName will be fetched dynamically, nothing will be hardcoded. Table1.ColumnName will be fetched from another subquery which runs perfectly.
My Question would be,
How to find which value in the particular subquery returned two rows.

How to find which value in the particular subquery returned two rows.
You need to check each sub-query whether it returns a single-row or multiple-rows for a value. You can use the COUNT function to verify -
select column_name, count(*) from table_name
group by column_name
having count(*) > 1
The above is the sub-query for which it checks the count of rows grouped by each value, if any value returns more than one row, that value is the culprit.
Once you get to know which sub-query and respective column is the culprit, you coulkd then use ROWNUM or ANALYTIC functions to limit the number of rows.

Related

Subquery returns unexpected results with WHERE, but works fine with JOIN

I want to get random quotes from db, I'm using this query:
SELECT * FROM quote WHERE quote.id = (SELECT id FROM quote ORDER BY RAND() LIMIT 1)
but I didn't get result time to time. Seems like subquery returns id that is not exists.
Subquery is working fine separately. And I didn't get id that is not exists.
And this query with JOIN instead WHERE works fine too.
SELECT * FROM quote JOIN (SELECT id FROM quote ORDER BY RAND() LIMIT 1) q1 ON quote.id = q1.id
Note: I can't use just subquery that returns whole quote, because I need to use some addition JOINs in main query. With these JOINs and without - result is the same.
There is a big difference between a subquery in the WHERE criteria of the first query and a derived table from table expression of the second query. They only look the same.
RAND() function is non-deterministic, non-deterministic functions may return different results for the same arguments. Usage of this function in a subquery makes the whole subquery non-deteministic. Non-deterministic subqueries are executed every time when their values are needed and here they are actually needed multiple times.
When outer query reads a row, it needs to verify that it matches the WHERE criteria, but non-deterministic subquery returns random results and this check will fail if id of checked row is different from random id returned from a subquery.
If id column is indexed (most likely it is), the subquery is executed first time to create an index condition and second time to check the WHERE criteria, if it isn't, the subquery is executed for each row from the first table to check the same WHERE criteria, in either case the outer query may return no results.
When the second query (with a join) is executed, its table value expressions, including that derived table, are constructed first, before any other steps of query execution. So there is only one execution of SELECT id FROM quote ORDER BY RAND() LIMIT 1, a derived table produced by this inner query isn't modified after that, so everything works as you expect.

Null Handling in SQL Queries

I have the following table:
All records
I want to get records satisfying some set of conditions.
Below is the query and it returns 3 results:
Records satisfying query
Now I want records which did not satisfy remaining records (i.e. records which did not satisfy conditions in the previous query) and I expect total 4 rows in return. So I am executing the query:
Query for remaining records
However, record number 4 is not returned and I know that col2 values 'null' is causing this problem.
I even tried with NVL and coalesce function but without any luck:
nvl_coalesce_queries
So basically, I want 4 rows in 'NOT' query.
Please let me know if any suggestions.
Use something like
select *
from tmp_dbg3
where col0 not in (select col0 from tmp_dbg3 where <your 'satisfying' condition>)
Try using the NOT IN operator:
https://technet.microsoft.com/en-us/library/ms189062(v=sql.105).aspx
SELECT * FROM database
WHERE id NOT IN (SELECT id FROM database WHERE *your conditions*)
I am assuming that the first column in your database is the auto increment key. I would personally prefer to use that to identify which columns are not in your conditions instead of col1.

Counting results in SQLite, given query with functions

As you may (or may not) already know, SQLite does not provide information about total number of results from the query. One has to wrap the query in SELECT count(*) FROM (original query); in order to get row count.
This worked perfectly fine for me, until one of users created custom SQL function (you can define your own functions in SQLite) that does INSERT into another, unrelated table. Then he executes query:
SELECT customFunction() FROM primaryTable WHERE primaryKeyColumnId = 1;
The query returns always 1 row, that is certain. It turns out that customFunction() was called twice (and inserted to that other table 2 rows) and that's because my application called his query as usuall and then called count(*) on that query as a followup.
How to approach this problem? How to execute only the original query and still have a row count from SQLite?
I'm using SQLite (3.13.0) C API.
You either have to remove such function calls from the query, or you cannot get the row count before actually having stepped through all the result rows.

row num gives zero records

I need to get the total no of records in a table for pagination purpose..it has some around 1 million records...the count is calculated as part of page load..i can do count query but it takes little more time thus increasing the time to page load.So to avoid that i have used
select ROW_NUMS,OWNER from ALL_TABLES where table_name='table1'
But the problem is that this query for some tables gives result as zero and also sometimes the count is not correct(different from count query)
any idea how to update the all_tables data for a table and how all_table
If You want the exact number of records in a table, You need to select count(*). This result will be correct. NUM_ROWS has never been to provide the exact number of rows.
You can gather the table, but this will give you the estimate count.
exec dbms_stats.gather_table_stats('<OWNER>', '<TABLE_NAME>');
To get an accurate row count you can get the database to do the heavy lifting before it sends the data to the client, e.g.:
SELECT t.*
,COUNT(*) OVER () AS row_count
FROM my_table t;
You need to run ANALYZE statement to properly update that column

SQL - Using MAX in a WHERE clause

Assume value is an int and the following query is valid:
SELECT blah
FROM table
WHERE attribute = value
Though MAX(expression) returns int, the following is not valid:
SELECT blah
FROM table
WHERE attribute = MAX(expression)
OF course the desired effect can be achieved using a subquery, but my question is why was SQL designed this way - is there some reason why this sort of thing is not allowed? Students coming from programming languages where you can always replace a data-type by a function call that returns that type find this issue confusing. Is there an explanation one can give them rather than just saying "that's the way it is"?
It's just because of the order of operations of a query.
FROM clause
WHERE clause
GROUP BY clause
HAVING clause
SELECT clause
ORDER BY clause
WHERE just filters the rows returned by FROM. An aggregate function like MAX() can't have a result returned because it hasn't even been applied to anything.
That's also the reason, why you can't use aliases defined in the SELECT clause in a WHERE clause, but you can use aliases defined in FROM clause.
A where clause checks every row to see if it matches the conditions specified.
A max computes a single value from a row set. If you put a max, or any other aggregate function into a where clause, how can SQL server figure out what rows the max function can use until the where clause has finished it filter?
This deals with the order that SQL Server processes commands in. It runs the WHERE clause before a GROUP BY or any aggregate. Since a where clause runs first, SQL Server can't tell if a row will be included in an aggregate until it processes the where. That is what the HAVING clause is for. HAVING runs after the GROUP BY and the WHERE and can include MAX since you have already filtered out the rows you don't want to use. See http://www.bennadel.com/blog/70-SQL-Query-Order-of-Operations.htm for a good explanation of the order in which SQL commands run.
Maybe this work
SELECT blah
FROM table
WHERE attribute = (SELECT MAX(expresion) FROM table1)
The WHERE clause is specifically designed to test conditions against raw data (individual rows of the table). However, MAX is an aggregate function over multiple rows of data. Basically, without a sub-select, the WHERE clause knows nothing about any rows in the table except for the current row. So how can you determine the maximum value over a whole bunch of rows when you don't even know what those rows are?
Yes, it's a little bit of a simplification, especially when dealing with joins, but the same principle applies. WHERE is always row-by-row, so that's all it really knows about.
Even if you have a GROUP BY clause, the WHERE clause still only processes one row at a time in the raw data before grouping. It doesn't know the value of a column in any other rows, so it has no way of knowing which row has the maximum value.
Assuming this is MS SQL Server, the following would work.
SELECT TOP 1 blah
FROM table
ORDER BY expression DESC