MySQL: One statement in one table - mysql

I need help :( I have table like this...
ID|code|item|user|
01|aaaa|1111|0001|
02|bbbb|1111|0001|
03|cccc|1111|0001|
04|dddd|1111|0001|
05|aaaa|1111|0002|
06|eeee|1111|0002|
07|ffff|1111|0001|
I'm user 0002 and I know my item numer (for example 1111). I don't know other users, ids and other codes, but i have to get only 02,03,04,07 results (for this example). Any sinle and duplicated rows (for code column) with user 002 should be ignored... if you know what i mean. Any ideas how? :(

This can be done with a subquery filter
select *
from myTable
where code not in (
select code
from myTable
where user = '0002'
)

Try with:
select ID
from myTable
where user <> '0002'
group by ID, code
having count(code) = 1

Related

SQL: Return immediately if one matched record found

I have one table with user and their posts. It looks like "user_id | post_id | post_status".
Now I have a list of userid (ex, 100 users) and I want to know how many of them has at least one post that gets deleted (ex, post_status 3).
Here is my sample search:
select count(distinct user_id)
from post_table
where user_id in ( {my set} )
and post_status=3
It runs super slow since it iterates the entire table. Is there a way to speed up the query?
Use something like
SELECT COUNT(*)
FROM
-- the list of userid as a rowset
( SELECT 123 AS user_id UNION ALL
SELECT 456 UNION ALL
-- ...
SELECT 789
) user_id_list
WHERE EXISTS ( SELECT NULL
FROM post_table
WHERE post_table.user_id = user_id_list.user_id
AND post_table.post_status = 3 )
If your MySQL version is 8.0.4 or above then you may provide the users list as CSV/JSON and parse it using JSON_TABLE (the query text will be more compact).
INDEX(post_status, user_id)
may help speed up your query, especially if very few rows have status=3.
This could also speed up Akina's solution.

mySQL SELECT values from a TABLE where the TABLE name is based on a field value

Here's are very simplified versions of my tables.
[stock_adjust]
id
batch_table_name
batch_id
adjustment_reason
qty
[ingredient_batch]
id
batch_name
...lots of other columns
[product_batch]
id
batch_name
...lots of other columns
[packaging_batch
id
batch_name
...lots of other columns
stock_adjust contains the name of the correct batch table in the column batch_table_name which will either be "ingredient_batch", "product_batch" or "packaging_batch". I need to get the values from the correct batch table for each entry. The pseudo code for this would look something like the following:
SELECT sa.id, sa.adjustment_reason, sa.qty, batch.batch_name
FROM stock_adjust AS sa, [sa.batch_table_name] AS batch
WHERE sa.batch_id=batch.id
I have tried to simplify the description and tables as much as possible, hopefully I haven't simplified it too much and the above makes sense?
I have found several questions regarding similar issues to the following, but they either do not work correctly in this situation or I am not understanding the question correctly.
While I would recommend updating your database schema, here's an approach that could work for you given your scenario:
select sa.id, b.batch_name
from stock_adjust sa join (
select id, batch_name, 'ingredient_batch' table_name from ingredient_batch
union all
select id, batch_name, 'product_branch' table_name from product_branch
union all
select id, batch_name, 'packaging_batch' table_name from packaging_batch
) b on sa.batch_table_id = b.id and b.table_name = sa.batch_table_name
SQL Fiddle Demo
Maybee a dynamic query could be the solution. Check this answer SELECT * FROM #variable

SQL: have duplicates for each ID, I would like to keep the ID with site that is not blank

ID Site
a www.google.com
a
b www.qq.com
b
c www.hodes.com
.
.
.
I have a table like the one above, I'd like to extract the the site value is not blank, such as:
ID Site
a www.google.com
b www.qq.com
c www.hodes.com
You just have to check if the content of the column site is null or not. In order to select the rows with content:
SELECT * FROM TABLE_NAME WHERE SITE IS NOT NULL
Read more here.
select * from table where Site <> '' or Site is not null
will work if the blank ones are ALWAYS duplicates.
otherwise
select max(id), max(site) from table group by id
Should be okay
select
ID,
max(if(trim(site) = '', null, site)) as site
from tbl
group by ID
;
You could substitute GROUP_CONCAT for max if more than one site per ID.
I'm gonna go on a limb and assume that you want to remove the empty rows from your database. If that's not the case, just move the where clause to a Select statement.
Delete from TableName where ISNULL(Site, '')=''
If you must return one and only one record per id, then your code must
cope with potential multiple records per id -- and you need the max() and group by .
I would suggest:
Select id, max(site)
from table_name
where nvl(site,0) <> 0
group by id
Else if you know that you'd never encounter multiple records with the same id:
Select id, site
from table_name
where nvl(site,0) <> 0

Get a list of ids not present in a table

I have a list of ids, and I want to query a mysql table for ids not present in the table.
e.g.
list_of_ids = [1,2,4]
mysql table
id
1
3
5
6
..
Query should return [2,4] because those are the ids not in the table
since we cant view ur code i can only work on asumption
Try this anyway
SELECT id FROM list_of_ids
WHERE id NOT IN (SELECT id
FROM table)
I hope this helps
There is a horrible text-based hack:
SELECT
substr(result,2,length(result)-2) AS notmatched
FROM (
SELECT
#set:=replace(#set,concat(',',id,','),',') AS result
FROM (
select #set:=concat(',',
'1,2,4' -- your list here
,',')
) AS setinit,
tablename --Your tablename here
) AS innerview
ORDER BY LENGTH(result)
LIMIT 1;
If you represent your ids as a derived table, then you can do this directly in SQL:
select list.val
from (select 1 as val union all
select 2 union all
select 4
) list left outer join
t
on t.id = list.val
where t.id is null;
SQL doesn't really have a "list" type, so your question is ambiguous. If you mean a comma separated string, then a text hack might work. If you mean a table, then something like this might work. If you are constructing the SQL statement, I would advise you to go down this route, because it should be more efficient.

How to find the next record after a specified one in SQL?

I'd like to use a single SQL query (in MySQL) to find the record which comes after one that I specify.
I.e., if the table has:
id, fruit
-- -----
1 apples
2 pears
3 oranges
I'd like to be able to do a query like:
SELECT * FROM table where previous_record has id=1 order by id;
(clearly that's not real SQL syntax, I'm just using pseudo-SQL to illustrate what I'm trying to achieve)
which would return:
2, pears
My current solution is just to fetch all the records, and look through them in PHP, but that's slower than I'd like. Is there a quicker way to do it?
I'd be happy with something that returned two rows -- i.e. the one with the specified value and the following row.
EDIT: Sorry, my question was badly worded. Unfortunately, my definition of "next" is not based on ID, but on alphabetical order of fruit name. Hence, my example above is wrong, and should return oranges, as it comes alphabetically next after apples. Is there a way to do the comparison on strings instead of ids?
After the question's edit and the simplification below, we can change it to
SELECT id FROM table WHERE fruit > 'apples' ORDER BY fruit LIMIT 1
SELECT * FROM table WHERE id > 1 ORDER BY id LIMIT 1
Even simpler
UPDATE:
SELECT * FROM table WHERE fruit > 'apples' ORDER BY fruit LIMIT 1
So simple, and no gymnastics required
Select * from Table
where id =
(Select Max(id) from Table
where id < #Id)
or, based on the string #fruitName = 'apples', or 'oranges' etc...
Select * from Table
where id =
(Select Max(id) from Table
where id < (Select id from Table
Where fruit = #fruitName))
I'm not familiar with the MySQL syntax, but with SQL Server you can do something with "top", for example:
SELECT TOP 1 * FROM table WHERE id > 1 ORDER BY id;
This assumes that the id field is unique. If it is not unique (say, a foreign key), you can do something similar and then join back against the same table.
Since I don't use MySQL, I am not sure of the syntax, but would imagine it to be similar.
Unless you specify a sort order, I don't believe the concepts of "previous" or "next" are available to you in SQL. You aren't guaranteed a particular order by the RDBMS by default. If you can sort by some column into ascending or descending order that's another matter.
This should work. The string 'apples' will need to be a parameter.
Fill in that parameter with a string, and this query will return the entire record for the first fruit after that item, in alphabetical order.
Unlike the LIMIT 1 approach, this should be platform-independent.
--STEP THREE: Get the full record w/the ID we found in step 2
select *
from
fruits fr
,(
--STEP TWO: Get the ID # of the name we found in step 1
select
min(vendor_id) min_id
from
fruits fr1
,(
--STEP ONE: Get the next name after "apples"
select min(name) next_name
from fruits frx
where frx.name > 'apples'
) minval
where fr1.name = minval.next_name
) x
where fr.vendor_id = x.min_id;
The equivalent to the LIMIT 1 approach in Oracle (just for reference) would be this:
select *
from
(
select *
from fruits frx
where frx.name > 'apples'
order by name
)
where rownum = 1
I don't know MySQL SQL but I still try
select n.id
from fruit n
, fruit p
where n.id = p.id + 1;
edit:
select n.id, n.fruitname
from fruits n
, fruits p
where n.id = p.id + 1;
edit two:
Jason Lepack has said that that doesn't work when there are gaps and that is true and I should read the question better.
I should have used analytics to sort the results on fruitname
select id
, fruitname
, lead(id) over (order by fruitname) id_next
, lead(fruitname) over (order by fruitname) fruitname_next
from fruits;
If you are using MS SQL Server 2008 (not sure if available for previous versions)...
In the event that you are trying to find the next record and you do not have a unique ID to reference in an applicable manner, try using ROW_NUMBER(). See this link
Depending on how savvy your T-SQL skill is, you can create row numbers based on your sorting order. Then you can find more than just the previous and next record. Utilize it in views or sub-queries to find another record relative to the current record's row number.
SELECT cur.id as id, nxt.id as nextId, prev.id as prevId FROM video as cur
LEFT JOIN video as nxt ON nxt.id > cur.id
LEFT JOIN video as prev ON prev.id < cur.id
WHERE cur.id = 12
ORDER BY prev.id DESC, nxt.id ASC
LIMIT 1
If you want the item with previous and next item this query lets you do just that.
This also allows You to have gaps in the data!
How about this:
Select * from table where id = 1 + 1