My query is:
SELECT * FROM table WHERE id IN (1,2,3,4);
I use it for usergroups and a user can be in more than one group. but it seems that when a record has multiple id like 1 and 3, mySQL does not return that row.
Is there any way to get that row too?
Your query translates to
SELECT * FROM table WHERE id='1' or id='2' or id='3' or id='4';
It will only return the results that match it.
One way of solving it avoiding the complexity would be, chaning the datatype to SET.
Then you could use, FIND_IN_SET
SELECT * FROM table WHERE FIND_IN_SET('1', id);
You have wrong database design and you should take a time to read something about database normalization (wikipedia / stackoverflow).
I assume your table looks somewhat like this
TABLE
group_id
user_ids
name
1
1,4,6
group1
2
4,5,1
group2
so in your table of user groups, each row represents one group and in user_ids column you have set of user ids assigned to that group.
Normalized version of this table would look like this
GROUP
id
name
1
group1
2
group2
GROUP_USER_ASSIGNMENT
group_id
user_id
1
1
1
4
1
6
2
4
Then you can easily select all users with assigned group, or all users in group, or all groups of user, or whatever you can think of. Also, your sql query will work:
/* Your query to select assignments */
SELECT * FROM `group_user_assignment` WHERE user_id IN (1,2,3,4);
/* Select only some users */
SELECT * FROM `group_user_assignment` t1
JOIN `group` t2 ON t2.id = t1.group_id
WHERE user_id IN (1,4);
/* Select all groups of user */
SELECT * FROM `group_user_assignment` t1
JOIN `group` t2 ON t2.id = t1.group_id
WHERE t1.`user_id` = 1;
/* Select all users of group */
SELECT * FROM `group_user_assignment` t1
JOIN `group` t2 ON t2.id = t1.group_id
WHERE t1.`group_id` = 1;
/* Count number of groups user is in */
SELECT COUNT(*) AS `groups_count` FROM `group_user_assignment` WHERE `user_id` = 1;
/* Count number of users in group */
SELECT COUNT(*) AS `users_count` FROM `group_user_assignment` WHERE `group_id` = 1;
This way it will be also easier to update database, when you would like to add new assignment, you just simply insert new row in group_user_assignment, when you want to remove assignment you just delete row in group_user_assignment.
In your database design, to update assignments, you would have to get your assignment set from database, process it and update and then write back to database.
Here is sqlFiddle to play with.
you must have record in table or array record in database.
example:
SELECT * FROM tabel_record
WHERE table_record.fieldName IN (SELECT fieldName FROM table_reference);
Related
the sql as follows come from mysql document. it is:
SELECT * FROM t1 AS t
WHERE 2 = (SELECT COUNT(*) FROM t1 WHERE t1.id = t.id);
The document say It finds all rows in table t1 containing a value that occurs twice in a given column , and doesnot explain the sql.
t1 and t is the same table, so the
count(*) in subquery == select count(*) from t
, isn't it?
count(*) in subquery == select count(*) from t
is wrong. because in mysql you can't use it like that. so you have to run it like that to get result of same id having two rows.
if you want to get count of same occurrence,
SELECT id, name, count(*) AS all_count FROM t1 GROUP BY id HAVING all_count > 1 ORDER BY all_count DESC
And also you can get values as your query like this as well,
select * from t1 where id in ( select id from t1 group by id having count(*) > 1 )
The query contains a correlated subquery in WHERE clause:
SELECT COUNT(*) FROM t1 WHERE t1.id = t.id
It is called correlated because it is related to the main query via t.id. So, this subquery counts the number of records having an id value that is equal to the current id value of the record returned by the main query.
Thus, predicate
(SELECT COUNT(*) FROM t1 WHERE t1.id = t.id) = 2
evaluates to true for any row with an id value that occurs twice in the table.
SELECT * FROM t1 AS t
WHERE 2 = (SELECT COUNT(*) FROM t1 WHERE t1.id = t.id);
This query goes through each record in t1 and then in the subquery looks into t1 again to see if in this case id is found 2 times (and only 2 times). You can do the same for any other column in t1 (or any table for that matter).
When you would like to see all values that are multiple times in the table, change WHERE 2 = by WHERE 1 <. This will also give you the values that are 3 times, 4 times, etc. in the table.
{
SELECT id,count( * )
FROM
MyTable
group by id
having count( * )>1
}
with this code, you can see the rows which repet more than one,
and you can change this query by yourself
How about using GROUP BY and HAVING:
SELECT id, count(1) as Total FROM MyTable AS t1
GROUP BY t1.id
HAVING Total = 2
I have a table where I store items and the time where they are relevant. For this question the following columns are relevant:
CREATE TABLE my_items
(
id INTEGER,
category INTEGER,
t DOUBLE
);
I want to select all items from a specific category (e.g. 1) and the sets of items that have a time within +- 5 (seconds) from these items.
I will probably do this with two types of queries in a script:
SELECT id,t from my_items where category=1;
then loop over the result set, using each result row's time as t_q1, and do a separate query:
SELECT id from my_items where t >= t_q1-5 AND t <= t_q1+5;
How can I do this in one query?
You can use a join. Take your subquery that selects all category 1 items, and join it with the original table on the condition that the time is within +/- five. It's possible that duplicate rows are returned, so you can group by id to avoid that:
SELECT t.*
FROM myTable t
JOIN (SELECT id, timeCol FROM myTable WHERE category = 1) t1
ON t.timeCol BETWEEN (t1.timeCol - 5) AND (t1.timeCol + 5)
OR t.id = t1.id
GROUP BY t.id;
I added the OR t.id = t1.id to make sure that the rows of category 1 are still included.
You can use a single query with all you criteria if there is only one table
SELECT id,t from my_items where category=1 AND t >= t_q1-5 AND t <= t_q1+5;
If there is two tables, use a right join on the timestamps table for performance.
select id
from my_items i,
(select min(t) min_t, max(t) max_t from my_items where category=1) i2
where i.category = 1 or
i.t between i2.min_t-5 and i2.max_t+5
Consider a table like this:
The id column is set to auto-increment, update_time column is supposed to be the date that the row was inserted in the table.
I want to simply get the latest entry for a user with user_id = x, I found out there are some ways:
SELECT * FROM mytable WHERE user_id = x ORDER BY update_time DESC LIMIT 1
And
SELECT * FROM mytable WHERE user_id = x MAX(update_time)
And another query would be selecting the row with highest id number
I am not quite sure about the syntax of the later one (please correct me).
This may seem to be a trivial task, but there was a case that someone else has altered the auto_increment value on the table, and sometimes the time of the server has changed (well this has not been happened in my case but what if it does!!?)
What would be the safest query to get the latest entry row for a user_id ( I mean a query to return weigh, height and activity_level for a user with user_id = x)
Do I need to add more columns to the table? if so, what?
I like the join approach for this. Assumes that userID + update_time is unique...it'll pull back multiple rows if it isn't.
select user_id, max(update_time) maxtime from table group by user_id
Simple statement to get the max update time by user ID. Use it as a subquery with inner join (inner join will function as a filter)
select t.*
from table t
inner join
(select user_id, max(update_time) maxtime
from table group by user_id
--where user_id = x
)a
on a.user_id = t.user_id and a.maxtime = t.update_time
I commented out the where user_id = x line...the advantage to this method is you can get all users and their most recent at once.
SELECT * FROM mytable WHERE user_id = x AND update_time = (SELECT MAX(update_time) FROM mytable WHERE user_id = x)
This really does not have to be so complicated:
SELECT id
FROM table
WHERE user_id = x
ORDER BY update_time DESC
LIMIT 1
This version will be the quickest, simplest, and easiest to read. It is a win in every regard.
I am trying to perform a search on a table with structure like
id, mls_id, address, agent_id. What I would like to do is pull all the records for agent_id but not pull more than one if there is same mls. For example:
Select * From table WHERE agent_ID = 1234
might pull up 5 records but let's say two of the records have an mls_id that is the same. Is there a way to just pull one of those and still keep all the other results in tact?
This seems to do the trick:
What it does is to choose the record with the minimal id from those that have the same mls_id
SELECT id, mls_id, address, agent_id
FROM MyTable t1
WHERE t1.agent_id=1 AND t1.id =
(SELECT Min(t2.id)
FROM MyTable t2
WHERE agent_id=1 AND t2.mls_id=t1.mls_id
GROUP BY t2.mls_id)
Here is the fiddle example : SqlFiddle
SELECT DISTINCT *
FROM table
WHERE agent_ID = 1234
Using the DISTINCT keyword will drop duplicate records from your result set.
I have a table defined like this:
CREATE TABLE mytable (id INT NOT NULL AUTO_INCREMENT, PRIMARY KEY(id),
user_id INT REFERENCES user(id) ON UPDATE CASCASE ON DELETE RESTRICT,
amount REAL NOT NULL CHECK (amount > 0),
record_date DATE NOT NULL
);
CREATE UNIQUE INDEX idxu_mybl_key ON mytable (user_id, amount, record_date);
I want to write a query that will have two columns:
user_id
amount
There should be only ONE entry in the returned result set for a given user. Furthermore, the amount figure returned should be the last recoreded amount for the user (i.e. MAX(record_date).
The complication arises because weights are recorded on different dates for different users, so there is no single LAST record_date for all users.
How may I write (preferably an ANSI SQL) query to return the columns mentioned previously, but ensuring that its only the amount for the last recorded amount for the user that is returned?
As an aside, it is probably a good idea to return the 'record_date' column as well in the query, so that it is eas(ier) to verify that the query is working as required.
I am using MySQL as my backend db, but ideally the query should be db agnostic (i.e. ANSI SQL) if possible.
First you need the last record_date for each user:
select user_id, max(record_date) as last_record_date
from mytable
group by user_id
Now, you can join previous query with mytable itself to get amount for this record_date:
select
t1.user_id, last_record_date, amount
from
mytable t1
inner join
( select user_id, max(record_date) as last_record_date
from mytable
group by user_id
) t2
on t1.user_id = t2.user_id
and t1.record_date = t2.last_record_date
A problem appears becuase a user can have several rows for same last_record_date (with different amounts). Then you should get one of them, sample (getting the max of the different amounts):
select
t1.user_id, t1.record_date as last_record_date, max(t1.amount)
from
mytable t1
inner join
( select user_id, max(record_date) as last_record_date
from mytable
group by user_id
) t2
on t1.user_id = t2.user_id
and t1.record_date = t2.last_record_date
group by t1.user_id, t1.record_date
I do not now about MySQL but in general SQL you need a sub-query for that. You must join the query that calculates the greatest record_date with the original one that calculates the corresponding amount. Roughly like this:
SELECT B.*
FROM
(select user_id, max(record_date) max_date from mytable group by user_id) A
join
mytable B
on A.user_id = B.user_id and A.max_date = B.record_date
SELECT datatable.* FROM
mytable AS datatable
INNER JOIN (
SELECT user_id,max(record_date) AS max_record_date FROM mytable GROUP BS user_id
) AS selectortable ON
selectortable.user_id=datatable.user_id
AND
selectortable.max_record_date=datatable.record_date
in some SQLs you might need
SELECT MAX(user_id), ...
in the selectortable view instead of simply SELECT user_id,...
The definition of maximum: there is no larger(or: "more recent") value than this one. This naturally leads to a NOT EXISTS query, which should be available in any DBMS.
SELECT user_id, amount
FROM mytable mt
WHERE mt.user_id = $user
AND NOT EXISTS ( SELECT *
FROM mytable nx
WHERE nx.user_id = mt.user_id
AND nx.record_date > mt.record_date
)
;
BTW: your table definition allows more than one record to exist for a given {id,date}, but with different amounts. This query will return them all.