Find the First occurrence value of data in Query - ms-access

I have a table that has a lot of data, but only of four categories. I would like to return the ID of the First occurrence and last occurrence, of the type. The following is the simplified version of my data..
ID | FName | Password | Category | Outcome
-----------------------------------------------------------------
1 | Dan | something | NEW | 8
2 | Faye | another | NEW | 1
:
:
189 | Chris | Password | OLD | 2
190 | Matt | Milk | OLD | 7
:
:
1169 | Mark | Dog | LITE | 3
1170 | Nick | Land | LITE | 1
So I would like to have a query that will return the result as
CATEGORY | ID_START | ID_END
----------------------------------------
NEW | 1 | 188
OLD | 189 | 1168
LITE | 1169 | 9999
I am using Access 2010. Any help greatly appreciated.

I can sugest this:
select category, min(id) as idStart, max(id) as idEnd
from tbl
group by category
Hope this helps you

Related

Whats the best way to store different prices for one entity in SQL?

So I am building a webpage that shows a bunch of video games located in a SQL database and one suggestion I had was to have the different prices from each region display based on a drop down. My question is trying to figure out whats the best way to store int in the database. Would it be like:
GAME
CountryID
price1
CountryID
price2
CountryID
price3 ...
Or is there a better way to do this?
Just a heads up I've only been developing web applications for a year or so and I'm still pretty new to SQL.
Thanks for your input!
I would use multiple tables, one for games and one for region pricing.
Games
+--------+----------+
| GameID | GameName |
+--------+----------+
| 1 | Game1 |
| 2 | Game2 |
| 3 | Game3 |
| 4 | Game4 |
+--------+----------+
RegionPricing
+----------+--------+-------+
| RegionID | GameID | Price |
+----------+--------+-------+
| 1 | 1 | 60 |
| 1 | 2 | 55 |
| 1 | 3 | 45 |
| 1 | 4 | 80 |
| 2 | 1 | 50 |
| 3 | 2 | 30 |
| 3 | 3 | 25 |
| 3 | 4 | 45 |
| 4 | 1 | 60 |
| 4 | 2 | 55 |
| 4 | 3 | 45 |
| 4 | 4 | 80 |
+----------+--------+-------+
By using separate tables you minimize duplicate data and allow for easy granular changes. You may also consider adding a column to RegionPricing for currency. This would also need a Region table, with RegionID and RegionName.

Pulling latest values using distinct and max

I have a table that looks like this if I 'select *'
+----+--------+------+------------+
| id | name | task | day |
+----+--------+------+------------+
| 1 | Rodney | 2 | 2016-05-05 |
| 2 | Rodney | 2 | 2016-05-08 |
| 3 | Rodney | 8 | 2016-05-08 |
| 4 | Scott | 2 | 2016-05-05 |
| 5 | Scott | 8 | 2016-05-05 |
| 6 | Frank | 2 | 2016-05-05 |
| 7 | Frank | 2 | 2016-05-08 |
+----+--------+------+------------+
What I'm trying to achive is a query that will get the last entered 'task' for each person. So, in this case I would want back:
2 | Rodney | 2 | 2016-05-08
3 | Rodney | 8 | 2016-05-08
4 | Scott | 2 | 2016-05-05
5 | Scott | 8 | 2016-05-05
7 | Frank | 2 | 2016-05-08
I'm pretty sure I need to use distinct against name & task and max for the most recent entry. Just not sure how to structure the two of them together to get the result.
select distinct name, task from test;
Gets me close...
+--------+------+
| name | task |
+--------+------+
| Rodney | 2 |
| Rodney | 8 |
| Scott | 2 |
| Scott | 8 |
| Frank | 2 |
+--------+------+
But no date...My SQL is limited. Any help would be appreciated.
Aggregate your rows so as to get the latest day per name. Then access the table again to get the records matching thse days:
select *
from test
where (name, day) in
(
select name, max(day)
from test
group by name
);
Another way is to select the records for which not exists a later record for the same name:
select *
from test
where not exists
(
select *
from test later
where later.name = test.name
and later.day > test.day
);

Remove duplicates SQL while ignoring key and selecting max of specified column

I have the following sample data:
| key_id | name | name_id | data_id |
+--------+-------+---------+---------+
| 1 | jim | 23 | 098 |
| 2 | joe | 24 | 098 |
| 3 | john | 25 | 098 |
| 4 | jack | 26 | 098 |
| 5 | jim | 23 | 091 |
| 6 | jim | 23 | 090 |
I have tried this query:
INSERT INTO temp_table
SELECT
DISTINCT #key_id,
name,
name_id,
#data_id FROM table1,
I am trying to dedupe a table by all fields in a row.
My desired output:
| key_id | name | name_id | data_id |
+--------+-------+---------+---------+
| 1 | jim | 23 | 098 |
| 2 | joe | 24 | 098 |
| 3 | john | 25 | 098 |
| 4 | jack | 26 | 098 |
What I'm actually getting:
| key_id | name | name_id | data_id |
+--------+-------+---------+----------+
| 1 | jim | 23 | NULL |
| 2 | joe | 24 | NULL |
| 3 | john | 25 | NULL |
| 4 | jack | 26 | NULL |
I am able to dedupe the table, but I am setting the 'data_Id' value to NULL by attempting to override the field with '#'
Is there anyway to select distinct on all fields and while keeping the value for 'data_id'? I will take the highest or MAX data_id # if possible.
If you only want one row returned for a specific value (in this case, name), one option you have is to group by that value. This seems like a good approach because you also said you wanted the largest data_id for each name, so I would suggest grouping and using the MAX() aggregate function like this:
SELECT name, name_id, MAX(data_id) AS data_id
FROM myTable
GROUP BY name, name_id;
The only thing you should be aware of is the possibility that a name occurs multiple times under different name_ids. If that is possible in your table, you could group by the name_id too, which is what I did.
Since you stated you're not interested in the key_id but only the name, I just excluded it from the query altogether to get this:
| name | name_id | data_id |
+-------+---------+---------+
| jim | 23 | 098 |
| joe | 24 | 098 |
| john | 25 | 098 |
| jack | 26 | 098 |
Here is the SQL Fiddle example.
RENAME TABLE myTable to Old_mytable,
myTable2 to myTable
INSERT INTO myTable
SELECT *
FROM Old_myTable
GROUP BY name, name_id;
This groups my tables by the values I want to dedupe while still keeping structure and ignoring the 'Data_id' column

Select duplicate and keep the oldest (not based on ID)

Thanks for your help i'm stuck on this problem.
Let me explain it, i have this kind of table :
| domain | creationdate | value 1 | value 2 |
|--------|---------------------|---------|---------|
| abc | 2013-05-28 15:35:01 | value 1 | value 2 |
| abc | 2013-04-30 12:10:10 | value 1 | value 2 |
| aaa | 2011-04-02 13:10:10 | value 1 | value 2 |
| bbb | 2012-02-12 10:48:10 | value 1 | value 2 |
| bbb | 2013-04-15 07:15:23 | value 1 | value 2 |
And i want to select (with subqueries) this :
| domain | creationdate | value 1 | value 2 |
|--------|---------------------|---------|---------|
| abc | 2013-04-30 12:10:10 | value 1 | value 2 |
| aaa | 2011-04-02 13:10:10 | value 1 | value 2 |
| bbb | 2012-02-12 10:48:10 | value 1 | value 2 |
I tried to do a combinaison of subqueries with IN/NOT IN in WHERE clause and group by/having but i'm not able to obtain a proper result.
I also have another question to ask, if someone already faced this kind of problem i would be glad to hear how he managed to figure it out.
The records in the first table you see above are frequently (every ten mins) deleted/inserted. My aim is to make a copy (or maybe a view) of the result (without the duplicates entries) which will be used 24/7 by a postfix mail server. I heard that big views (with many subqueries) decreases performances which means a table would be a preferable option. The thing is if i have to make a new table every ten mins there will be a little down time and postfix will not be able to read the table.
Waiting for your advices, thanks already.
EDIT :
Based on #Ed Gibbs answer, there is a better sample :
Source table :
| domain | creationdate | value 1 | value 2 |
|------------|---------------------|---------|---------|
| google.com | 2013-05-28 15:35:01 | john | mary |
| google.com | 2013-04-30 12:10:10 | patrick | edward |
| yahoo.fr | 2011-04-02 13:10:10 | britney | garry |
| ebay.com | 2012-02-12 10:48:10 | harry | mickael |
| ebay.com | 2013-04-15 07:15:23 | bill | alice |
With your query the result is the source table.
Desired result :
| domain | value 1 | value 2 |
|------------|---------|---------|
| google.com | patrick | edward |
| yahoo.fr | britney | garry |
| ebay.com | harry | mickael |
I want to keep the oldest domain (with the min creation date) with its own value1 and 2.
New question !
I made a view of the desired result based on your anwser.
The result look like this :
| domain | value 1 | foreign_key |
|------------|---------|-------------|
| google.com | patrick | X |
| yahoo.fr | britney | Y |
| ebay.com | harry | Z |
I also have a table with this kind of entries :
| email | value 1 | foreign_key |
|--------------------|---------|-------------|
| john#google.com | patrick | X |
| john#google.com | britney | Y |
| harry#google.com | mary | X |
| mickael#google.com | jack | X |
| david#ebay.com | walter | Z |
| alice#yahoo.com | brian | Y |
Assume that (in this sample) emails %#google.com from Y foreign_key aren't good records (only %google.com from X foreign are the good ones and also because its domain is the one i choose with the creationdate selection) how could i manage to select only emails from domain/fk referenced in my new view ?
Desired result :
| email | value 1 | foreign_key |
|--------------------|---------|-------------|
| john#google.com | patrick | X |
| harry#google.com | mary | X |
| mickael#google.com | jack | X |
| david#ebay.com | walter | Z |
| alice#yahoo.com | brian | Y |
I tried with a CONCAT('%','#',domain) and a foreign_key=foreign_key join but it doesn't give me what i want.
Based on your sample data and results, a GROUP BY will give you the results you're after:
SELECT
domain,
MIN(creationdate) AS creationdate,
value1,
value2
FROM mytable
GROUP BY domain, value1, value2
Addendum: #Arka provided updated sample data where the value 1 and value 2 columns have different values (in the original they were the same). That changes the query to this:
SELECT domain, creationdate, value1, value2
FROM mytable
WHERE (domain, creationdate) IN (
SELECT domain, MIN(creationdate)
FROM mytable
GROUP BY domain)
The subquery gets a list of the earliest creationdate for each domain, and the outer query only selects rows where the domain and creationdate match the subquery values.

Assistance with database design

I've got a excel sheet that contains all the employees that have worked for my company and is still working for us. It's a sheet of around 200 rows. Each row has basic info, like surname, name, position, qualification etc etc. 16 columns of basic info. Now, the tricky part is this. After the 16 columns, there are months (May-05 up to the present (Apr-12)). Under every month column, an employee either get's a 0 (contract), 1 (permanent), 2 (contract-terminated) or 3 (student).
What would be the best way to do this? I was thinking of 4 tables (listed below), where the one table determines permanently terminated people (for the sake of knowing who was on what type of employment).
MySQL Table: hr_employees
|-----------------|-------|----|----|----|
| employee_number | name | sur| etc| etc|
|-----------------|-------|----|----|----|
| 1 | Dave | F | xx | xx |
|-----------------|-------|----|----|----|
MySQL Table: hr_month
|----|--------|
| id | month |
|----|--------|
| 1 | May-05 |
| 2 | Jun-05 |
|----|--------|
MySQL Table: hr_status
|----|------|------|--------|
| id | e_no | date | status |
|----|------|------|--------|
| 1 | 1 | 1 | 1 |
| 2 | 1 | 2 | 1 |
|----|------|------|--------|
MySQL Table: hr_terminated
|----|------|
| id | e_no |
|----|------|
| 1 | 1 |
| 2 | 1 |
|----|------|
I hope you guys understand what I want to achieve, otherwise, ask a question, and I'll answer as best I can! :)
Thanks.
Here is a design that simplifies your data entry and is more relational database like and less Excel like, insofar as it's normalized.
MySQL Table: hr_employee
|-----------------|-------|----|----|----|
| employee_number | name | sur| etc| etc|
|-----------------|-------|----|----|----|
| 1 | Dave | F | xx | xx |
|-----------------|-------|----|----|----|
| 2 | Bob | M | xx | xx |
|-----------------|-------|----|----|----|
MySQL Table: hr_employee_status
|-----------------|------------|------------|--------|
| employee_number | from_date | to_date | status |
|-----------------|------------|------------|--------|
| 1 | 2005-05-01 | 2005-08-31 | 3 |
|-----------------|------------|------------|--------|
| 1 | 2006-05-01 | 2010-02-28 | 0 |
|-----------------|------------|------------|--------|
| 2 | 2010-03-01 | 9999-12-31 | 1 |
|-----------------|------------|------------|--------|
Here you can see that Dave was hired on as a student from May '05 to August '05, then he came back in May '06 as a contract employee which he worked as until the end of February '10. Then on March 1, 2010 Bob was hired as permanent employee and he is still working (max collating date means "until further notice").
The great advantage of this design is that you only have to enter/edit data when something changes, not once a month for every employee that you have or have ever had. You can also see what your workforce looked like at any given date (not just by months!) with a very simple SQL query.