I want to insert a condition in one of my queries, but don't really know how to do it.
Basically, I'm sorting a bunch of files by their folder _id, i.e. the folder they belong to (using order by folder_id). What I'd like now, for each of these groups of files, is the query to pick the first file that satisfies a particular condition. If that condition is not satisfied by any of the files in a folder, than the query should pick the first document available in the folder.
This is my query (simplified):
select folder_id,
file_id,
first_name
from f_file
where first_name = 'John'
order by folder_id
So, if my results now are:
FOLDER ID FILE ID AUTHOR
A 32 John
A 41 John
A 56 Thomas
A 78 Peter
B 02 Peter
B 03 Peter
B 45 Peter
C 34 John
C 56 Thomas
C 77 Peter
C 86 John
D 12 Peter
D 34 Thomas
D 89 Thomas
for each folder, I'd like the query to show only the first document (lowest file_id) that was created by John. If there are no documents created by John at all in that folder, than the first one from any other author will do.
FOLDER ID FILE ID AUTHOR
A 32 John
B 02 Peter
C 34 John
D 12 Peter
So, the ID has to be the lowest, but the Author has to be John or another one.
My idea would be to insert an IF EXISTS clause in the WHERE clause, but how to do it?
Thanks for your responses.
Val
Related
I have a list of data that happens to have been set up like this:
entryID fieldID Value
100 1 John
100 2 Smith
100 3 USA
101 1 Jane
101 2 Doe
101 3 USA
The way it works is, when a "ticket" is created, it assigns an entryID for all the data in that ticket, but each field also has it's own fieldID. So first name is always a fieldID of 1, last name is 2, etc.
What I need to be able to do is create a view that will look like this:
First Name Last Name Country
John Smith USA
Jane Doe USA
I need to be able to do this in MySQL, and not SQL or excel, as some other similar problems have addressed.
I just found the answer to my own question, so I will post it here for future users.
This website explains how to do exactly what I was asking for: http://stratosprovatopoulos.com/web-development/mysql/pivot-a-table-in-mysql/
This is my first post, so please forgive me for any formatting errors.
I need to find the time between each row of data for a large number of users, and then take the average of those times as a function of time. I know how to to do the latter part, I just don't know how to find the time differences between rows.
For example, I can generate this output very easily (for all users sequentially, just using 'John' as an example):
User order time
John 13 2013-10-31 22:35:19
John 12 2013-10-18 23:16:50
John 11 2012-12-07 00:38:34
John 10 2012-06-10 02:19:14
John 9 2010-07-02 00:55:54
John 8 2009-12-20 23:43:41
John 7 2009-12-20 01:14:32
John 6 2009-12-18 15:12:40
John 5 2009-12-13 00:38:38
John 4 2009-12-12 16:00:13
John 3 2009-12-12 14:50:18
John 2 2009-12-11 18:41:15
John 1 2009-12-04 03:12:06
But, what I need to find out how to do is create this:
User order time timeDiff
John 13 2013-10-31 22:35:19 13
John 12 2013-10-18 23:16:50 300
John 11 2012-12-07 00:38:34 170
John 10 2012-06-10 02:19:14 ...
John 9 2010-07-02 00:55:54 ...
John 8 2009-12-20 23:43:41 ...
John 7 2009-12-20 01:14:32 ...
John 6 2009-12-18 15:12:40 ...
John 5 2009-12-13 00:38:38 ...
John 4 2009-12-12 16:00:13 ...
John 3 2009-12-12 14:50:18 ...
John 2 2009-12-11 18:41:15 ...
John 1 2009-12-04 03:12:06 NULL
This is easily done in excel, but I need the grouping properties for users + dates in order to do some analysis.
All help appreciated!!
Try this
Select current.time - previous.time As TimeDiff
From UserTable current Join
UserTable previous On current.User = pervious.User And current.Order - 1 = previous.Order
Where current.User = 'John'
That should get you the time differences.
You said you knew how to get the average from there.
Like you said, it's easy in Excel. Referring to relative rows in SQL is pretty hard, especially in MySQL.
You have to use server-side variables to establish "state", so you can remember previous values. e.g.
SET prev := null;
SELECT User, Order, time, IF(#prev IS NOT NULL, time - #prev, null), #prev := time;
It gets even harder since you're doing this for multiple users, and will have to add extra code to detect when the user changes.
For this kind of thing, you're better off doing the calcs in client-side code. Which means just do:
SELECT User, Order, UNIX_TIMESTAMP(time)
...
ORDER BY User, Order
and then you can feed those timestamps directly to PHP's time system for formatting/calculations.
I tried to create a VIEW that merge some tables in order to have the "hottest" teacher in a educational platform.
First, I have a table with the users (some teachers, some students),
then in other I have the lessons created by the teachers,
finally, other one that has the relation between students and lesson.
when I use this SQL sentence
CREATE OR REPLACE VIEW `skn_teachers` AS
select
`u`.`id_skn_users` AS `id_skn_users`,
`u`.`firstName` AS `firstName`,
`u`.`lastName` AS `lastName`,
COUNT(`ls`.`createdBy`) AS `countLessons`
from (`skn_users` AS `u`, `skn_rolesxusers` AS `rxu`, `skn_roles` AS `ro`, `skn_approved_lessons` AS `ls`)
where ((`rxu`.`id_skn_users` = `u`.`id_skn_users`) and (`rxu`.`id_skn_roles` = `ro`.`id_skn_roles`) and (`ro`.`name` = 'teacher') and (`ls`.`createdBy` = `rxu`.`id_skn_users`))
group by `u`.`id_skn_users`
the row countLessons show me the number of lessons per teacher eg.
id | firstName | lastName | countLessons
1 Pepito Perez 1
2 Julián Figueroa 7
3 Daniel Aguirre 2
which is correctly the number of lessons per teacher.
but I need the number of students that have the lessons created by each teacher (all of them, sum of all students in all lessons of THAT teacher), countStudentsByTeacher, in one of my attempts, get this SQl and it was a surprise when I got the number of students by teacher but I don't understand clearly what I did.
new SQL sentence:
CREATE OR REPLACE VIEW `skn_teachers` AS
select
`u`.`id_skn_users` AS `id_skn_users`,
`u`.`firstName` AS `firstName`,
`u`.`lastName` AS `lastName`,
COUNT(`ls`.`createdBy`) AS `countStudents`
from (`skn_users` AS `u`, `skn_rolesxusers` AS `rxu`, `skn_roles` AS `ro`, `skn_approved_lessons` AS `ls`, `skn_lessonsxusers` AS `lxu`)
where ((`rxu`.`id_skn_users` = `u`.`id_skn_users`) and (`rxu`.`id_skn_roles` = `ro`.`id_skn_roles`) and (`ro`.`name` = 'teacher') and (`ls`.`createdBy` = `rxu`.`id_skn_users`) and (`ls`.`id_skn_lessons` = `lxu`.`id_skn_lessons`))
group by `u`.`id_skn_users`
//
id | firstName | lastName | countLessons
1 Pepito Perez 10
2 Julián Figueroa 15
3 Daniel Aguirre 8
here, column countLessons shows really the number of students into all lessons created by each teacher, exactly what I wanted but I want to know why this works.
Thanks in advance!
In your 2nd query, you added at join to the table skn_lessonsxusers. This causes the 2nd query to return additional rows per each student that was assigned the lesson. The first query only returned the lessons that were created by each teacher.
Example:
Looking at the teacher "Daniel Aguirre", the underlying non-aggregated data for the first query might look like this:
id | firstName | lastName | Lesson
3 Daniel Aguirre Math 101
3 Daniel Aguirre CS 104
So there are 2 lessons that he teaches.
Now if you add in the students for each lesson, i.e. the 2nd query, then the data might look like this.
id | firstName | lastName | Lesson | Student
3 Daniel Aguirre Math 101 John
3 Daniel Aguirre Math 101 Bob
3 Daniel Aguirre Math 101 Sara
3 Daniel Aguirre Math 101 Mary
3 Daniel Aguirre CS 104 John
3 Daniel Aguirre CS 104 Bob
3 Daniel Aguirre CS 104 Dan
3 Daniel Aguirre CS 104 Sally
So now when you aggregate this 2nd set of data, it will show a count of 8 because there are 8 student/lesson combination for Daniel Aguirre.
Now assuming that John and Bob in the above 2nd data set are the same student, there are not really 8 different students taking lessons from Daniel Aguirre, there are 6 (John, Bob, Sara, Mary, Dan, and Sally). If you wanted to show 6 in this example you would use:
COUNT(DISTINCT `lxu`.`student_id`) AS `countStudents`
where student_id is the column that represents a unique student in the skn_lessonsxusers table. NOTE: your column is probably a different name than "student_id", but I don't know your table structure for this example so I just used "student_id".
It works because you multiply each lesson by each student in this lesson
join... 'skn_approved_lessons' AS 'ls'
where... and ('ls'.'createdBy' = 'rxu'.'id_skn_users')
I'm working on a project where I'm dumping data into a mysql database about different people, however, each person can have many entries so I'm not sure how to have a lot of columns.
e.g
Name id
jack 234 01241990 13241990 03451993 10945
james 222 01131998 14242001 03414235 10945435 3456363 3465758
jill 1234 01131998 14242001 03414235 10945435 3456363 3465758 4253156316 6427247 583583
As you can see there can be many entries for each person, not in 100's, but I think the max can be around 20-30ish? So how do I build a database that I can insert values into without knowing how many entries will be per person, beforehand.
I am using perl script to insert values. Any ideas will be helpful
EDIT: People are suggesting to create two tables, however, when I joint he tables, I want one row for each person.
e.g After joining my view should look like
james 222 01131998 14242001 03414235 10945435 3456363 3465758
My suggestion would be to split the data into two tables (People and Data):
People:
NAME ID
Jack 234
James 222
Jill 1234
Data:
ID PeopleID Data
1 234 01241990
2 234 13241990
.
.
99 1234 6427247
100 1234 583583
You can then use joins to get the data for each person
SELECT p.Name,
p.ID,
d.Data
FROM People p
JOIN Data d
ON d.PeopleID = p.ID
ORDER BY p.Name --(assuming you want names in alphabetical order)
You should get something like the following
Name ID Data
Jack 234 01241990
Jack 234 13241990
.
.
Jill 1234 6427247
Jill 1234 583583
I have this sql table with people's name and ages.
Bob 28
Bryan 30
Jim 25
John 42
Bill 22
Sam 28
Tom 26
I would like to make a sql command to order all people by age desc, find a name in it, a return the preceding one, the founded and the next one with their position.
For example, admit that I would like to find Tom, my request should return :
Name Age Rank
Jim 25 2
Tom 26 3
Bob 28 4
Jim has the number 2 because Bill is the youngest
Is it possible to do something like this ?
Thanks in advance for any help
SQL isn't suited for row-based operations. There's no easy way to do "find a row where some condition(s) = true, then return the previous row" in a single query. You can do it in a couple steps, though:
a) Run one query to retrieve 'Tom' and his age (26).
b) Run another query to get the next older person
SELECT name, age FROM ... WHERE age > 26 ORDER BY age ASC LIMIT 1
c) Repeat but for next younger:
SELECT name, age FROM ... WHERE age < 26 ORDER BY age DESC LIMIT 1
This'll fetch people who are at least 1 year old/younger... You don't specify what happens if there's multiple people of the same age (e.g. There's Fred who's also 26, or Doug and Elmer who are both 25), so I'm ignoring those conditions.