Use value of a field from a table dynamically in the 'where' clause of a HQL query? - sql

Can one filter a table dynamically with a 'where' clause acting on a value of a field from another table under some other conditions such that it is made sure only one row is returned? Can I do something like this?
SELECT COUNT(*) FROM stud t1
WHERE t1.name==SELECT name FROM (
SELECT name, row_number() over (PARTITION BY name) AS rn
FROM stud t2) t3
WHERE t3.rn==1;
Of course, the above query is just a dummy one, but is filtering on where clause like above possible theoretically? If not how could one achieve such a functionality in the cases of more complex queries?

Yes. Query can be made like this:
SELECT COUNT(*) FROM stud t1
WHERE t1.name = (SELECT name
from sometable
where somecondition);
but you need to make sure that the subquery return zero or one row. If your query may return more than one row, you can use IN instead:
SELECT COUNT(*) FROM stud t1
WHERE t1.name IN (SELECT name
from sometable
where somecondition);

Related

How to avoid duplicates of a single ID in SQL; Select Distinct

I have some SQL code that reads like this. It intends to grab all of the data meeting the two conditions, but not to grab the data if we already have a row with the same ID as it. Select Distinct (t1.ID) works as intended, but when I add in the additional variables, it no longer filters properly.
Select Distinct (t1.ID),t1.Var2, t1.Var3...
FROM table_location AS t1
WHERE t1.FCT_BILL_CURRENCY_CODE_LCL = 'USD'
AND t1.RQ_GLOBAL_REGION = 'North America'
enter image description here
This clearly contains multiple rows with the same ID, contrary to how it should work. How do I fix this?
I'm not sure what DB you're using, but most will have the concept of numbering rows by a partition.
To get a distinct by a certain value, you need to make a subquery that selects your data plus a row number that is partitioned by your distinct property, then have your parent query select only the rows with 1 as the row number to get just the first of each.
I have added a query by looking into the sample query you mentioned in the problem. If you add sample data, the we will have better understanding of the problem.
Query
SELECT
ID,
Var2,
Var3
FROM (
SELECT
DENSE_RANK() OVER (PARTITION BY t1.ID ORDER BY t1.ID) AS Rnk_ID,
t1.ID,
t1.Var2,
t1.Var3
FROM table_location AS t1
WHERE t1.FCT_BILL_CURRENCY_CODE_LCL = 'USD'
AND t1.RQ_GLOBAL_REGION = 'North America'
) qry1
WHERE Rnk_ID = 1

Finding MAX id from table with conditions

There is a table with columns: id, name, age.
I need to find the max value of id and display name and id, where name starts with just A.
I used the query below to get the results, but this query doesn't return the unique row.
Its will retrieve from DB all rows where name start with, for example A, and all id's will be listed in the results set. My query HQL is:
SELECT t.name, MAX(t.id)
FROM table t
WHERE t.name LIKE 'A%' AND t.age= :age
GROUP BY t.name
The WHERE clause is filtering your data by the criteria you want, but it's SELECT and GROUPING by the name instead of just the first letter.
So what you need to do is 2 steps. First report the Max(ID) that satisfies your criteria. Next, you'll want to join that ID back to the data to retrieve the name.
So, this is your first into into the wonderful world of subqueries:
SELECT t1.*
FROM
table t1
INNER JOIN
(
SELECT MAX(id) AS max_id
FROM table
WHERE name LIKE 'A%' AND age= :age
) AS toprecord
ON t1.id = toprecord.max_id
I think you want this:
SELECT t.*
FROM table t
WHERE t.name LIKE 'A%' AND t.age= :age
ORDER BY t.id DESC
LIMIT 1;

SQLite how to get same groups by id?

I have a question about query. Here is my table:
I get id by onClick method and I want result like this. For example if id is 2 get all rows who has same group.
Result:
You can use a subquery:
select t.*
from mytable t
where t.group = (select t2.group from mytable t2 where t2.id = 2);
Note that group is a really bad name for a column, because it is a SQL keyword. It is fine for illustration.

Explain how this SELECT WHERE subquery works?

Here's the query:
SELECT ID, Name, EventTime, State
FROM mytable as mm Where EventTime IN
(Select MAX(EventTime) from mytable mt where mt.id=mm.id)
Here is the fiddle:
http://sqlfiddle.com/#!3/9630c0/5
It comes from this S.O. question:
Select distinct rows whilst grouping by max value
I would like to hear in plain english how it works. I'm missing some fundamental understanding of part of it.
I don't really understand what the aliases are doing in the mt.id=mm.id part. It selects rows where the id is equal to the id?
The mt.id=mm.id part makes it a correlated subquery, hence the subquery is re-evaluated for each ID.
The query, then, selects the most recent event for each ID.
It is basically translated into "Get me the data for each id with maximum EventTime associated with."
You can also rewrite the code as
SELECT t1.ID, t1.Name, t1.EventTime, t1.State FROM mytable as t1
inner join
(
select id,max(EventTime) as EventTime from mytable group by id
) as t2 on t1.id=t2.id and t1.EventTime=t2.EventTime

Implement FIRST() in select and not in WHERE

I want to get first value in a field in Oracle when another corresponding field has max value.
Normally, we would do this using a query and a subquery. The subquery ordering by a field and the outer query with where rownum<=1.
But, I cannot do this because the table aliases persist only one level deep and this query is a part of another big query and I need to use some aliases from the outermost query.
Here's the query structure
select
(
select a --This should get first value of a after b's are sorted desc
from
(
select a,b from table1 where table1.ID=t2.ID order by b desc
)
where rownum<=1
)
) as "A",
ID
from
table2 t2
Now this is not gonna work because alias t2 wont be available at innermost query.
Real world analogy that comes to my mind is I have a table containing records for all employees of a company, their salaries(including past salaries) and the date from which the salary was effective. So, for each employee, there will multiple records. Now, I want to get latest salaries for all the employees.
With SQL server, I could have used SELECT TOP. But that's not available with Oracle and since where clauses execute before order by, I cannot use where rownum<=1 and order by in same query and expect correct results.
How do I do this?
Using your analogy of employees and their salaries, if I understand what you are trying to do, you could do something like this (haven't tested):
SELECT *
FROM (
SELECT employee_id,
salary,
effective_date,
ROW_NUMBER() OVER (PARTITION BY employee_id ORDER BY effective_date DESC) rowno
FROM employees
)
WHERE rowno=1
I would much rather see you connect the subquery up with a JOIN instead of embedding it in the SELECT. Cleaner SQL. Then you can use the windowing function that roartechs suggests.
Select t2.whatever, t1.a
From table2 t2
Inner Join (
Select tfirst.ID, tfirst.a
From (
Select ID, a,
ROW_NUMBER() Over (Partition BY ID ORDER BY b DESC) rownumber
FROM table1
) tfirst
WHERE tfirst.rownumber=1
) t1 on t2.ID=t1.ID