Is there a way to use an ICriteria result as a 'base' for a subsequent criteria query?
For example if I would like to create a query
SELECT department_id, sum(cost) AS total
FROM payment
GROUP BY payment.department_id
storing the result as query0, and then execute the query
SELECT department.name, total
FROM department, query0
JOIN LEFT ON department.id=query0.id
WHERE total > 3
I do not want to have one single huge query executed all at once (which would be the result of creating an ICriteria with subqueries). Note that I have a selection/ restriction on a result of the first query and at the same time including one of its columns in the second query's projection.
The criteria is generated dynamically using strings to identify the classes.
The closest thing I can think of to this is a Common Table Expression (the SQL WITH statement). Unfortunately NHibernate doesn't seem to have any good abstractions for dealing with CTEs, but here is how your query might look in SQL Server:
WITH query0 AS (
SELECT department_id AS id, sum(cost) AS total
FROM payment
GROUP BY payment.department_id
)
SELECT department.name, total
FROM department, query0
WHERE department.id=query0.id
AND total > 3;
SQL Fiddle: http://sqlfiddle.com/#!3/8e6877/7
Related
SELECT
"employees"."FIRST_NAME",
"employees"."LAST_NAME",
"employees"."SALARY"
FROM
'employees'
WHERE
(("employees"."SALARY" > (SELECT "employees"."SALARY"
FROM 'employees'
WHERE (("employees"."FIRST_NAME" = "Alexander")))))`
The subquery returns 2 values. How can they be compared with "employees"."salary" ? That is, there are 2 employees with first name "Alexander"... Replacing the subquery with a 2 element tuple gives a query that is not accepted from the SQL client... That is this query should be equivalent to the one above but it does not execute correctly:
SELECT
"employees"."FIRST_NAME", "employees"."LAST_NAME",
"employees"."SALARY"
FROM
'employees'
WHERE
(("employees"."SALARY" > (3500, 9000)))
What is going on?
From SQL Language Expressions/11. Subquery Expressions:
A SELECT statement enclosed in parentheses is a subquery. All types of
SELECT statement, including aggregate and compound SELECT queries
(queries with keywords like UNION or EXCEPT) are allowed as scalar
subqueries. The value of a subquery expression is the first row of
the result from the enclosed SELECT statement. The value of a
subquery expression is NULL if the enclosed SELECT statement returns
no rows.
Your query would not run in any other database than SQLite.
But, SQLite as you can see from the documentation, instead of throwing an error like the subquery returns more than 1 rows, allows the subquery by keeping only the 1st of the rows that it returns.
This is one of SQLite's non-standard sql features and in your case it leads to wrong results.
What you would want, I believe, is to compare each employee's salary to the max salary of all employees named 'Alexander'.
You can do this by changing the subquery to:
SELECT MAX(SALARY) FROM employees WHERE FIRST_NAME = 'Alexander'
This is a not correlated scalar subquery, so there is no need for any aliases.
Note assuming that the SQLite tag is correct , i.e. there are many flavours of SQL and that the database manager being is used is therefore important and relevant.
the subquery returns 2 values. How can they be compared with "employees"."salary" ?
You compare multiple values using a function that can take multiple values such as max, which could be what you require.
e.g.
SELECT "employees"."FIRST_NAME", "employees"."LAST_NAME", "employees"."SALARY" FROM 'employees' WHERE (("employees"."SALARY" > max(3500, 9000)))
What is going on?
The first is using a WHERE clause that is a valid expression that is either true or false. The second is misusing values i.e. a list of values is provided where a single value is expected.
First, writing your queries, you should not have to "quote" every part, it gets cluttered and bloated. Also, you can use aliases to help readability. you'll see soon. If you use quotes, use the single quotes around specific values such as a date like > '2022-02-22'.
Now on to your query. Your query is looking for salaries greater than a given person (Alexander), but there are multiple people by that name. To get ONE answer, you might need the MAX() salary for the critiera. So this essentially becomes TWO queries... one relying upon the other.
So, to get you an answer, the outer query is what you will get as the results, the WHERE query is pre-qualifying that one salary you are interested in.
Select
e.first_name,
e.last_name,
e.salary
from
employees e
where
e.salary > ( select max( e2.salary )
from employees e2
where e2.first_name = 'Alexander' )
Notice the where clause is getting whatever the MAX() salary value is from the employee table for the employee 'Alexander'. So now, that ONE value comes back as the basis for the outer query.
Notice the indentation, you can better see how the outer query is reliant on that. Also makes for more readable queries.
So I'm kinda new to SQL and been following some tutorial courses online.
I want to compare the num_bikes_available at a station to the average num_bikes_available.
My question is why cant it just show the average using the OUTER SELECT clause? Why do it need to be done using SUBQUERY? My Answer. Tutorial Answer.
Query SELECT AVG(num_bikes_available) FROM citibike_stations will return a single row with average calculated over all rows.
Now, if you add station_id like SELECT station_id, AVG(num_bikes_available) FROM citibike_stations, this is also supposed to return a single row, but BigQuery does not know which exactly station_id value do you need. Therefore you see that error.
BigQuery can show average for every distinct station_id value it finds, but to do that it needs the GROUP BY clause like SELECT station_id, AVG(num_bikes_available) FROM citibike_stations GROUP BY station_id.
Using 'HAVING' without 'GROUP BY' is not allowed:
SELECT *
FROM products
HAVING unitprice > avg(unitprice)
Column 'products.UnitPrice' is invalid in the HAVING clause because it is not contained in either an aggregate function or the GROUP BY clause.
But when placing the same code under 'EXISTS' - no problems:
SELECT *
FROM products p
WHERE EXISTS (SELECT 1
FROM products
HAVING p.unitprice > avg(unitprice))
Can you please explain why?
well the error is clear in first query UnitPrice is not part of aggregation nor group by
whereas in your second query you are comparing p.unitprice from table "products p" which doesn't need to be part of aggregation or group by , your second query is equivalent to :
select * from products p
where p.unitprice > (select avg(unitprice) FROM products)
which maybe this is more clear , that sql caculate avg(unitprice) then compares it with unitprice column from product.
HAVING filters after aggregation according to the SQL standard and in most databases.
Without a GROUP BY, there is still aggregation.
But in your case, you simply want a subquery and WHERE:
SELECT p.*
FROM products p
WHERE p.unitprice > (SELECT AVG(p2.unitprice) FROM products p2);
The problem comes from the columns you select :
SELECT *
and
SELECT 1
Unlike ordinary functions that are evaluated at each row, aggregate functions are computed once the whole dataset is processed, which means that in theory (at least without a GROUP BY statement), you can't select both aggregate and regular functions in a same column set (even if some DBMS still tolerate this).
It's easier to see when considering SUM(). You're not supposed to have an access to the total of a column before all rows have been returned, which prevents you to write something like SELECT price,SUM(price), for instance.
GROUP BY, now, enables you to regroup your rows according to a given criteria (actually, a bunch of columns), which makes these aggregate functions to be computed at the end of each of these groups instead of the whole dataset. Therefore, since all the column specified in GROUP BY are supposed to be the same for a given group, you're allowed to include them in your global SELECT statement.
This leads us to the actual failure cause: on first query, you select all columns. On the second one, you select none: only the constant 1, which is not part of the table itself.
I have a table BAR_DATA with two fields: LongDate, Time. Both are long integers. No Access Date/Time involved here.
For each distinct LongDate value there are hundreds of records, each with Time value which may be distinct or duplicate within that LongDate.
I need to create an SQL statement that will group by LongDate and give me a count of distinct Times within each LongDate.
The following SQL statement, (built by an Acess query) does NOT work (some LongDates are omitted):
Query A
SELECT DISTINCT BAR_DATA.LongDate, Count(BAR_DATA.Time) AS CountOfTime
FROM BAR_DATA
GROUP BY BAR_DATA.LongDate
HAVING (((Count(BAR_DATA.Time))<>390 And (Count(BAR_DATA.Time))<>210));
However, if I use Query B to reference Query DistinctDateTime, it does work:
Query B
SELECT DistinctDateTime.LongDate, Count(DistinctDateTime.Time) AS CountOfTime
FROM DistinctDateTime
GROUP BY DistinctDateTime.LongDate
HAVING (((Count(DistinctDateTime.Time))<>390 And (Count(DistinctDateTime.Time))<>210));
Query DistinctDateTime
SELECT DISTINCT BAR_DATA.LongDate, BAR_DATA.Time
FROM BAR_DATA;
My problem:
I need to get Query B and Query DistinctDateTime wrapped into a single SQL statement so I can paste it into a VBA function. I presume there
is some subquery techniques, but I have failed at every attempt, and find no pertinent example.
Any help will be greatly appreciated. Thanks!
Subquery your distinct table inside and perform your aggregates outside until you get the desired result:
SELECT DistinctDateTime.LongDate, Count(DistinctDateTime.Time) AS CountOfTime
FROM
(
SELECT DISTINCT BAR_DATA.LongDate, BAR_DATA.Time
FROM BAR_DATA
) AS DistinctDateTime
GROUP BY DistinctDateTime.LongDate
HAVING (((Count(DistinctDateTime.Time))<>390 And (Count(DistinctDateTime.Time))<>210));
I am writing some queries with self-joins in SQL Server. When I have only one column in the SELECT clause, the query returns a certain number of rows. When I add another column, from the second instance of the table, to the SELECT clause, the results increase by 1000 rows!
How is this possible?
Thanks.
EDIT:
I have a subquery in the FROM clause, which is also a self-join on the same table.
How is this possible?
the only thing I can think of is that you have SELECT DISTINCT and the additional column makes some results distinct that weren't before the additional column.
For example I would expect the second result to have many more rows
SELECT DISTINCT First_name From Table
vs
SELECT DISTINCT First_name, Last_name From Table
But if we had the actual SQL then something else might come to mind