SQL Query for ID grouped AND WHERE otherfield has certain value - sql

I have a table in Access that is set up where there are multiple records with the same ID, they correspond to each other.
I'd like to find certain records that have a specific date value. However, I want all the corresponding information WITH that ID (i.e. all the other records with the same ID). I've tried things like this:
SELECT *
FROM myTable
WHERE LEFT(Field1,7) = '2016-11' IN (SELECT ID
FROM myTable
GROUP BY ID
HAVING COUNT(*)>1)
and
SELECT *
FROM myTable
WHERE ID = (SELECT * FROM myTable WHERE LEFT(Field1,7) = '2016-11'
Neither of these are giving me the proper output. I think I may need a For loop of some sort but don't have much experience doing this with SQL. That way I can loop through all IDs that are returned with that date-part. Any suggestions? I would put the table format in the post but the table formatting isn't working for me for some reason. The frustration is real!
Haha thanks ahead of time for taking the time to even read my question. Much appreciated.
EDIT
Here is a visual of what my table is like:
ExampleTable
I'd like to choose all the records that occur during November, but also get the corresponding information (i.e. records with same ID number as the November records).

Consider adding WHERE condition in subquery:
SELECT *
FROM myTable
WHERE ID IN (SELECT ID FROM myTable
WHERE LEFT(Field1, 7) = '2016-11');
Alternatively to avoid subquery, try an INNER JOIN on a filtered self join by ID:
SELECT myTable.*
FROM myTable
INNER JOIN
(SELECT ID FROM myTable
WHERE LEFT(Field1, 7) = '2016-11') sub
ON sub.ID = myTable.ID

Related

How can I make selection based on conditions on SQL?

There is a table based on ID an those ID's status keys:
The table
I need to write query that will bring higher status key of the same ID. For example; query will bring only the row with status key number 9 for ID number 123. But it will bring the row with status key number 2 for ID number 156.
Hope I managed to explain myself clearly. Please help me with this query.
Use max() aggregation
select id, max(status_key)
from tablename
group by id
You didn't tag your backend, this would work with many backends and older versions of many backends (assuming you have other columns too in your table - otherwise do only group by):
select myTable.*
from myTable
inner join
(select id, max(statusKey) as statusKey
from myTable
group by id) tmp on myTable.id = tmp.id and myTable.statusKey = tmp.statusKey;

Select row with max value with condition

I have a table that contains results of some sports competition. Here it is:
And I need to get a table with winner teams. It means, from rows with same MatchIds select entries where Score is maxium for these MatchIds.
Result should look like this:
I have no idea of correct SQL query.
I'm using MSSQL Server 2018. Thank you.
One method is a correlated subquery:
select t.*
from t
where t.score = (select max(t2.score) from t t2 where t2.matchid = t.matchid);

SQL select all columns for two distinct columns

The question might be not new but i need help from you .I have sql db table and i want to select all columns for the rows which have distinct values of two columns
.For instance i have a table named 'information' as below.
What i want is to select all rows with distinct values of 'ctc_card_no' and 'tarehe' .Can anyone please help me as i have struggled to get the results
I need results to be like
I think you want to use not exists:
select t.*
from t
where not exists (select 1
from t t2
where t2.ctc_card_no = t.ctc_card_no and t2.tarehe = t.tarehe and
t2.id <> t.id
);
This returns all rows that appear only once in the table, which is how I interpret your question.
EDIT:
If you just want the distinct pairs, you can use group by:
select min(id), ctc_card_no, tarehe
from t
group by ctc_card_no, tarehe;
Maybe something like this?
select *
from information
where (ctc_card_no, tarehe) in
(select ctc_card_no, tarehe
from information
group by ctc_card_no, tarehe
having count(*) = 1
);

sql query to get earliest date

If I have a table with columns id, name, score, date
and I wanted to run a sql query to get the record where id = 2 with the earliest date in the data set.
Can you do this within the query or do you need to loop after the fact?
I want to get all of the fields of that record..
If you just want the date:
SELECT MIN(date) as EarliestDate
FROM YourTable
WHERE id = 2
If you want all of the information:
SELECT TOP 1 id, name, score, date
FROM YourTable
WHERE id = 2
ORDER BY Date
Prevent loops when you can. Loops often lead to cursors, and cursors are almost never necessary and very often really inefficient.
SELECT TOP 1 ID, Name, Score, [Date]
FROM myTable
WHERE ID = 2
Order BY [Date]
While using TOP or a sub-query both work, I would break the problem into steps:
Find target record
SELECT MIN( date ) AS date, id
FROM myTable
WHERE id = 2
GROUP BY id
Join to get other fields
SELECT mt.id, mt.name, mt.score, mt.date
FROM myTable mt
INNER JOIN
(
SELECT MIN( date ) AS date, id
FROM myTable
WHERE id = 2
GROUP BY id
) x ON x.date = mt.date AND x.id = mt.id
While this solution, using derived tables, is longer, it is:
Easier to test
Self documenting
Extendable
It is easier to test as parts of the query can be run standalone.
It is self documenting as the query directly reflects the requirement
ie the derived table lists the row where id = 2 with the earliest date.
It is extendable as if another condition is required, this can be easily added to the derived table.
Try
select * from dataset
where id = 2
order by date limit 1
Been a while since I did sql, so this might need some tweaking.
Using "limit" and "top" will not work with all SQL servers (for example with Oracle).
You can try a more complex query in pure sql:
select mt1.id, mt1."name", mt1.score, mt1."date" from mytable mt1
where mt1.id=2
and mt1."date"= (select min(mt2."date") from mytable mt2 where mt2.id=2)

Correct sql/hql query (aggregate in where clause)

I want to do query as below. Query is wrong but describes my intentions.
SELECT name, dateTime, data
FROM Record
WHERE dateTime = MAX(dateTime)
Update: Ok. The query describes intentions not quite good. My bad.
I want to select latest record for each person.
Try This:
SELECT name, dateTime, data
FROM Record
WHERE dateTime = SELECT MAX(dateTime) FROM Record
You could also write it using an inner join:
SELECT R.name, R.dateTime, R.data
FROM Record R
INNER JOIN (SELECT MAX(dateTime) FROM Record) RMax ON R.dateTime = RMax.dateTime
Which is the same but written from a different perspective
SELECT R.name, R.dateTime, R.data
FROM Record R,
(SELECT MAX(dateTime) FROM Record) RMax
WHERE R.dateTime = RMax.dateTime
I like Miky's answer and the from Quassnoi (and upvoted Miky's) but, if your needs are similar to mine, you should keep in mind some limitations. First and most importantly, it only works if you are looking for the latest record overall or the latest record for a single name. If you want the latest record for each person in a set (one record per person but the latest record for each) then the above solutions fall short. Second, and less importantly, if you'll be working with large datasets, might prove a bit slow over the long run. So, what is the work-around?
What I do is to add a bit field to the table marked "newest." Then, when I store a record (which is done in a stored procedure in SQL Server) I follow this pattern:
Update Table Set Newest=0 Where Name=#Name
Insert into Table (Name, dateTimeVal, Data, Newest) Values (#Name, GetDate(), #Data, 1);
Also, there is an index on Name and Newest to make Selects very fast.
Then the Select is just:
Select dateTimeVal, Data From Table Where (Name=#Name) and (Newest=1);
A select for a group will be something like:
Select Name, dateTimeVal, Data from Table Where (Newest=1); -- Gets multiple records
If the records may not be entered in date order, then your logic is a little bit different:
Update Table Set Newest=0 Where Name=#Name
Insert into Table (Name, dateTimeVal, Data, Newest) Values (#Name, GetDate(), #Data, 0); -- NOTE ZERO
Update Table Set Newest=1 Where dateTimeVal=(Select Max(dateTimeVal) From Table Where Name=#Name);
The rest stays the same.
In MySQL and PostgreSQL:
SELECT name, dateTime, data
FROM Record
ORDER BY
dateTime DESC
LIMIT 1
In SQL Server:
SELECT TOP 1 name, dateTime, data
FROM Record
ORDER BY
dateTime DESC
In Oracle
SELECT *
FROM (
SELECT name, dateTime, data
FROM Record
ORDER BY
dateTime DESC
)
WHERE rownum = 1
Update:
To select one person for each record, in SQL Server, use this:
WITH q AS
(
SELECT *, ROW_NUMBER() OVER (PARTITION BY person ORDER BY dateTime DESC)
FROM Record
)
SELECT *
FROM q
WHERE rn = 1
or this:
SELECT ro.*
FROM (
SELECT DISTINCT person
FROM Record
) d
CROSS APPLY
(
SELECT TOP 1 *
FROM Record r
WHERE r.person = d.person
ORDER BY
dateTime DESC
) ro
See this article in my blog:
SQL Server: Selecting records holding group-wise maximum
for benefits and drawbacks of both solutions.
I tried Milky's advice but all three ways of constructing subquery resulted in HQL parser errors.
What does work though, is a slight change to the first method (added extra parentheses).
SELECT name, dateTime, data
FROM Record
WHERE dateTime = (SELECT MAX(dateTime) FROM Record)
PS: This is just for pointing out the obvious to HQL newbies and the like. Thought it would help.