SQL Subquery in VB.Net with Access Database - sql

I have developed an SQL query that uses sub-query based on a result set (i.e. a query queries the results of a sub-query). The query executes as expected in MS Access but will not execute in vb.net (including query builder). The error I receive in query builder is:
Error in WHERE clause near 'ORDER'. Unable to parse query text.
I understand that a typical sub-query selects based on the WHERE clause whereas my SQL is querying based on the FROM clause. Because Access doesn't support the LIMIT command, I can't figure out how structure this SQL so it will run in VB.NET. If the LIMIT command was supported I think I could structure the sub-query properly.
Here is my SQL:
SELECT AVG(Differential) * .96
FROM
(SELECT TOP 5 Differential
FROM
(SELECT TOP 10 GameDate, Differential
FROM ScoringHistory
WHERE PlayerID = ?
ORDER BY GameDate DESC)
ORDER BY Differential ASC, GameDate DESC)
If I change PlayerID = ? to PlayerID = 1 (which is a valid value), query builder gives me the same error as above but I can execute the query in query builder.
I've also tried importing (?) the query from Access into VB.NET and I get the same error.
Any suggestions on how to structure my query so it will execute properly?
Adding more information:
I am implementing via a table adapter. See image.
Selecting the query and clicking configure displays the following
Then if I click on the Query Builder button I get this error:
Error Message
My code to implement the query looks like this:
Dim factor As Single
factor = ScoringHistoryTableAdapter.CalculateFactor(1)

i think you are missing alis name or your subquery
SELECT AVG(Differential) * .96
FROM
(SELECT TOP 5 Differential
FROM
(SELECT TOP 10 GameDate, Differential
FROM ScoringHistory
WHERE PlayerID = 1
ORDER BY GameDate DESC) a
ORDER BY Differential ASC, GameDate DESC) b

It looks like your OrderBy clauses are reversed.
You're ordering by GameDate in the middle From clause, but GameDate isn't included in that Select, only Differential.
Try:
SELECT AVG(Differential) * .96
FROM (
SELECT TOP 5 Differential
FROM (
SELECT TOP 10 GameDate, Differential
FROM ScoringHistory
WHERE PlayerID = ?
ORDER BY Differential ASC,GameDate DESC
)
ORDER BY Differential DESC
)

As the original poster I thought I would close the loop for everyone on this.
A little more research indicates that this is a known problem(?) with sub queries and the table adapter wizard. Now knowing this, i learned how to execute SQL the old fashioned way and used ExecuteScalar as Charles had indicated and the SQL works fine.

Related

SQL Server - Pagination Without Order By Clause

My situation is that a SQL statement which is not predictable, is given to the program and I need to do pagination on top of it. The final SQL statement would be similar to the following one:
SELECT * FROM (*Given SQL Statement*) b
OFFSET 0 ROWS FETCH NEXT 50 ROWS ONLY;
The problem here is that the *Given SQL Statement* is unpredictable. It may or may not contain order by clause. I am not able to change the query result of this SQL Statement and I need to do pagination on it.
I searched for solution on the Internet, but all of them suggested to use an arbitrary column, like primary key, in order by clause. But it will change the original order.
The short answer is that it can't be done, or at least can't be done properly.
The problem is that SQL Server (or any RDBMS) does not and can not guarantee the order of the records returned from a query without an order by clause.
This means that you can't use paging on such queries.
Further more, if you use an order by clause on a column that appears multiple times in your resultset, the order of the result set is still not guaranteed inside groups of values in said column - quick example:
;WITH cte (a, b)
AS
(
SELECT 1, 'a'
UNION ALL
SELECT 1, 'b'
UNION ALL
SELECT 2, 'a'
UNION ALL
SELECT 2, 'b'
)
SELECT *
FROM cte
ORDER BY a
Both result sets are valid, and you can't know in advance what will you get:
a b
-----
1 b
1 a
2 b
2 a
a b
-----
1 a
1 b
2 a
2 b
(and of course, you might get other sorts)
The problem here is that the *Given SQL Statement" is unpredictable. It may or may not contain order by clause.
your inner query(unpredictable sql statement) should not contain order by,even if it contains,order is not guaranteed.
To get guaranteed order,you have to order by some column.for the results to be deterministic,the ordered column/columns should be unique
Please note: what I'm about to suggest is probably horribly inefficient and should really only be used to help you go back to the project leader and tell them that pagination of an unordered query should not be done. Having said that...
From your comments you say you are able to change the SQL statement before it is executed.
You could write the results of the original query to a temporary table, adding row count field to be used for subsequent pagination ordering.
Therefore any original ordering is preserved and you can now paginate.
But of course the reason for needing pagination in the first place is to avoid sending large amounts of data to the client application. Although this does prevent that, you will still be copying data to a temp table which, depending on the row size and count, could be very slow.
You also have the problem that the page size is coming from the client as part of the SQL statement. Parsing the statement to pick that out could be tricky.
As other notified using anyway without using a sorted query will not be safe, But as you know about it and search about it, I can suggest using a query like this (But not recommended as a good way)
;with cte as (
select *,
row_number() over (order by (select 0)) rn
from (
-- Your query
) t
)
select *
from cte
where rn between (#pageNumber-1)*#pageSize+1 and #pageNumber*#pageSize
[SQL Fiddle Demo]
I finally found a simple way to do it without any order by on a specific column:
declare #start AS INTEGER = 1, #count AS INTEGER = 5;
select * from (SELECT *,ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS fakeCounter
FROM (select * from mytable) AS t) AS t2 order by fakeCounter OFFSET #start ROWS
FETCH NEXT #count ROWS ONLY
where select * from mytable can be any query

SQL for getting each category data in maria db

I need to fetch 4 random values from each category. What should be the correct sql syntax for maria db. I have attached one image of table structure.
Please click here to check the structure
Should i write some procedure or i can do it with basic sql syntax?
You can do that with a SQL statement if you only have a few rows:
SELECT id, question, ... FROM x1 ORDER BY rand() LIMIT 1
This works fine if you have only a few rows - as soon as you have thousands of rows the overhead for sorting the rows becomes important, you have to sort all rows for getting only one row.
A trickier but better solution would be:
SELECT id, question from x1 JOIN (SELECT CEIL(RAND() * (SELECT(MAX(id)) FROM x1)) AS id) as id using(id);
Running EXPLAIN on both SELECTS will show you the difference...
If you need random value for different categories combine the selects via union and add a where clause
http://mysql.rjweb.org/doc.php/groupwise_max#top_n_in_each_group
But then ORDER BY category, RAND(). (Your category is the blog's province.)
Notice how it uses #variables to do the counting.
If you have MariaDB 10.2, then use one of its Windowing functions.
SELECT column FROM table WHERE category_id = XXX
ORDER BY RAND()
LIMIT 4
do it for all categories

Jet-SQL to TSQL

In MS Access 2010 I have the following code:
SELECT
[Teile-LF-Beziehungen].Lieferant,
COUNT([Teile-LF-Beziehungen].Lieferant) AS [Anz Teile],
First([Teile-LF-Beziehungen].Name) AS Name
FROM
[Teile-LF-Beziehungen]
GROUP BY
[Teile-LF-Beziehungen].Lieferant
ORDER BY
COUNT([Teile-LF-Beziehungen].Lieferant) DESC;
I want to put that query into SQL Server, because MS Access should be only the frontend.
But in SQL Server I can't use the ORDER in a view. But why? I don't understand it. The code I want to use in SQL Server:
SELECT
[Lieferant],
COUNT([Lieferant]) AS [Anz Teile],
MIN([Name]) AS [Name]
FROM
[dbo].[VIEW_Teile-LF-Beziehungen]
GROUP BY
[Lieferant]
ORDER BY
COUNT([Lieferant]) DESC;
I know it don't work. But is there any way to incur a MS Access query 1:1 to a SQL Server query (view)?
Only the outermost select can use an order by (but you might state a TOP 100 percent to trick this out). Therefore it is perfectly OK, that at VIEW does not allow this.
Many people think, that tables have kind of an implicit order (as you see the result ordered), but this is random... The next call could lead to a different sorting.
There is another way using ROW_NUMBER with OVER(ORDER BY). The result is delivered in this order and the order is guaranteed as long the orderby is sorting after unique values.
EDIT
Sorry my first attempt was to quick. The ROW_NUMBER was not allowed due to the grouping
This should work:
SELECT tbl.Lieferant
,tbl.[Anz Teile]
,tbl.Name
,ROW_NUMBER() OVER(ORDER BY tbl.[Anz Teile] DESC) AS Sort
FROM
(
SELECT [Lieferant]
,COUNT([Lieferant]) AS [Anz Teile]
,MIN([Name]) AS [Name]
FROM [dbo].[VIEW_Teile-LF-Beziehungen]
GROUP BY [Lieferant]
) AS tbl;
EDIT2
This SELECT can be placed within a VIEW, just place your CREATE VIEW YourViewName AS before the SELECT and execute. After this you'll be able to do a SELECT * FROM YourViewName to get a sorted list.
BUT
As stated in many places: The best is the outermost ORDER BY in any case!
ORDER BY doesnt work inside the view. SQL server is free to return the rows anyway he want if you dont include the order by when calling the View
So you need
SELECT *
FROM yourView
ORDER BY yourField
EDIT: Im saying if your view is
CREATE VIEW yourView AS
SELECT
[Lieferant],
COUNT([Lieferant]) AS [Anz Teile],
MIN([Name]) AS [Name]
FROM
[dbo].[VIEW_Teile-LF-Beziehungen]
GROUP BY
[Lieferant];
Then you call your View like this
SELECT *
FROM yourView
ORDER BY [Anz Teile]

TOP function in SQL Server 2005 not giving correct answer

How can I use TOP function in SQL Server 2005 on a single column in a table along with count function?
I am getting only one count for this query, where I have 35 entries that should come.
this is my query
select top(1) room_no, count(room_no) from rooms
Seems like what you want is the following:
select room_no,count(room_no)
from rooms
group by room_no
BTW, I wonder why it would execute without the group by. Should throw an error.
COUNT function is evaluated after TOP. That is why you are only getting one for the count. What you want is something like this
SELECT TOP(1) dbo.Table.Column1, (SELECT COUNT(*) FROM dbo.Table)
FROM dbo.Table
Also as mentioned you really should be ordering by something.
Edit: This also works:
SELECT TOP(1) dbo.Table.Column1, COUNT(*) OVER() AS Total
FROM dbo.Table
Seems to be more efficient as well (only tested on small dataset though).

Paging with Oracle and sql server and generic paging method

I want to implement paging in a gridview or in an html table which I will fill using ajax. How should I write queries to support paging? For example if pagesize is 20 and when the user clicks page 3, rows between 41 and 60 must be shown on table. At first I can get all records and put them into cache but I think this is the wrong way. Because data can be very huge and data can be change from other sessions. so how can I implement this? Is there any generic way ( for all databases ) ?
As others have suggested, you can use rownum in Oracle. It's a little tricky though and you have to nest your query twice.
For example, to paginate the query
select first_name from some_table order by first_name
you need to nest it like this
select first_name from
(select rownum as rn, first_name from
(select first_name from some_table order by first_name)
) where rn > 100 and rn <= 200
The reason for this is that rownum is determined after the where clause and before the order by clause. To see what I mean, you can query
select rownum,first_name from some_table order by first_name
and you might get
4 Diane
2 Norm
3 Sam
1 Woody
That's because oracle evaluates the where clause (none in this case), then assigns rownums, then sorts the results by first_name. You have to nest the query so it uses the rownum assigned after the rows have been sorted.
The second nesting has to do with how rownum is treated in a where condition. Basically, if you query "where rownum > 100" then you get no results. It's a chicken and egg thing where it can't return any rows until it finds rownum > 100, but since it's not returning any rows it never increments rownum, so it never counts to 100. Ugh. The second level of nesting solves this. Note it must alias the rownum column at this point.
Lastly, your order by clause must make the query deterministic. For example, if you have John Doe and John Smith, and you order by first name only, then the two can switch places from one execution of the query to the next.
There are articles here http://www.oracle.com/technology/oramag/oracle/06-sep/o56asktom.html
and here http://www.oracle.com/technology/oramag/oracle/07-jan/o17asktom.html. Now that I see how long my post is, I probably should have just posted those links...
Unfortunately, the methods for restricting the range of rows returned by a query vary from one DBMS to another: Oracle uses ROWNUM (see ocdecio's answer), but ROWNUM won't work in SQL Server.
Perhaps you can encapsulate these differences with a function that takes a given SQL statement and first and last row numbers and generates the appropriate paginatd SQL for the target DBMS - i.e. something like:
sql = paginated ('select empno, ename from emp where job = ?', 101, 150)
which would return
'select * from (select v.*, ROWNUM rn from ('
+ theSql
+ ') v where rownum < 150) where rn >= 101'
for Oracle and something else for SQL Server.
However, note that the Oracle solution is adding a new column RN to the results that you'll need to deal with.
I believe that both have a ROWNUM analytic Function. Use that and you'll be identical.
In Oracle it is here
ROW_NUMBER
Yep, just verified that ROW_NUMBER is the same function in both.
"Because...data can be change from other sessions."
What do you want to happen for this ?
For example, user gets the 'latest' ten rows at 10:30.
At 10:31, 3 new rows are added (so those ten being view by the user are no longer the latest).
At 10:32, the user requests then 'next' ten entries.
Do you want that new set to include those three that have been bumped from 8/9/10 down to 11/12/13 ?
If not, in Oracle you can select the data as it was at 10:30
SELECT * FROM table_1 as of timestamp (timestamp '2009-01-29 10:30:00');
You still need the row_number logic, eg
select * from
(SELECT a.*, row_number() over (order by hire_date) rn
FROM hr.employees as of timestamp (timestamp '2009-01-29 10:30:00') a)
where rn between 10 and 19
select *
from ( select /*+ FIRST_ROWS(n) */ a.*,
ROWNUM rnum
from ( your_query_goes_here,
with order by ) a
where ROWNUM <=
:MAX_ROW_TO_FETCH )
where rnum >= :MIN_ROW_TO_FETCH;
Step 1: your query with order by
Step 2: select a.*, ROWNUM rnum from ()a where ROWNUM <=:MAX_ROW_TO_FETCH
Step 3: select * from ( ) where rnum >= :MIN_ROW_TO_FETCH;
put 1 in 2 and 2 in 3
If the expected data set is huge, I'd recommend to create a temp table, a view or a snapshot (materialized view) to store the query results + a row number retrieved either using ROWNUM or ROW_NUMBER analytic function. After that you can simply query this temp storage using row number ranges.
Basically, you need to separate the actual data fetch from the paging.
There is no uniform way to ensure paging across various RDBMS products. Oracle gives you rownum which you can use in where clause like:
where rownum < 1000
SQL Server gives you row_id( ) function which can be used similar to Oracle's rownum. However, row_id( ) isn't available before SQL Server 2005.