Update all rows but one using SQL query - mysql

I have a table like so
+-------------------------------------+
| Description | ID | Show(1 or 0) |
+-------------------------------------+
I have a bunch of entries with the same description but one has an ID of null. I have to set show on all the rows without the null to 0 but only if they have more than rows 2 of the same description. I am new to SQL and I have around 50K rows so I would rather not do it manually.
USA 987655 1 - changed to 0
USA 987658 1 - changed to 0
USA 987617 1 - changed to 0
USA 989876 null - unchanged
CAN 767655 1 - not changed
CAN 957655 1 - not changed
have tried:
UPDATE test1 t1,
(
SELECT id, description, show AS mid
FROM test1 ti
GROUP BY
description
) tm
SET show = 0
WHERE t1.description= tm.description
AND id is not null;
Thank you in advance

You'll need a correlated sub-query. I haven't tested this, so use with caution. But something like this might be what you're after.
UPDATE
some_table st1
JOIN (
SELECT st2.description, count(*) c
FROM some_table st2
WHERE
st1.description = st1.description AND
st1.id IS NOT NULL AND
st2.id IS NOT NULL
GROUP by st2.description
HAVING c > 1
) AS tmp ON tmp.description = st1.description
SET st1.show = 0

This is not the final answer but could help you a lot ( i guess)
execute this query to see which ones should be updated from 0 to 1
SELECT description, COUNT(*) as "Same Description" FROM table
WHERE id <> null
GROUP BY description
HAVING COUNT(*) > 2

Related

Select rows where column > 0 after final row where column == 0

Edit 2021: I want to explain this better.
I have a table named MyTable with two columns; one column named SortColumn type Integer and one column named ExpressionColumn type Boolean.
I want to get all rows, sorted by SortColumn in ascending order, after the last row where ExpressionColumn was True.
The types are not exact.
Eg. Table with rows represented as [SortColumn,ExpressionColumn], [0:True] will get [0:True], [0:True, 1:False] will get [], [0:True, 1:False, 2:True, 3:True] will get [3:True, 4:True].
Leaving the old question below so as not to invalidate given answers. It had too many extra details.
I want to select rows after than last row where column Number is 0.
So with this table,
Id | Number
------------
0 | 5
1 | 30
2 | 10
3 | 25
I want to get rows with Id 0 to 3 inclusive.
With this table,
Id | Number
------------
0 | 5
1 | 30
2 | 10
3 | 25
4 | 0
I want to get no rows at all.
With this table,
Id | Number
------------
0 | 5
1 | 30
2 | 10
3 | 25
4 | 0
5 | 0
6 | 30
I want to get row with Id 6.
SQL details: MySQL 5.6.
Retrieve separate records:
SELECT *
FROM transaction t1
WHERE Name LIKE '%Car Wash%'
AND NOT EXISTS ( SELECT NULL
FROM transaction
WHERE t1.id <= id
AND Name LIKE '%Car Wash%' -- maybe not needed? not specified
AND Price = 0 );
Retrieve their amount only:
SELECT COUNT(*)
FROM transaction t1
WHERE Name LIKE '%Car Wash%'
AND NOT EXISTS ( SELECT NULL
FROM transaction
WHERE t1.id <= id
AND Name LIKE '%Car Wash%'
AND Price = 0 );
fiddle
you can select
select
from my_table
where name like '%car%' and price > 0
and for count
select count(*)
from (
select
from my_table
where name like '%car%' and price > 0
) t
I interpret this question as "how many rows are there for "car wash" after the first row with price > 0". If so:
select count(*)
from (select t.*,
min(case when price = 0 then id end) over () as id_at_0
from transaction t
) t
where name = 'Car Wash' and id > id_at_0
SELECT * FROM MyTable myTable1
AND NOT EXISTS ( SELECT NULL FROM MyTable
WHERE myTable1.SortColumn <= SortColumn
AND ExpressionColumn = True );

How can i find missing id's in mysql

i have a large MySQL Database with more than 1 Million rows. How can i find the missing eid's?
+----+-----+
| id | eid |
+----+-----+
| 1 | 1 |
+----+-----+
| 2 | 2 |
+----+-----+
| 3 | 4 |
+----+-----+
I like to list all missing eid's, the 3 in this example. I've tried many things but everything what i do need to much time.
I hope someone can help me.
Thanks
You can use NOT EXISTS to find the required rows.
create table t(id integer, eid integer);
insert into t values(1,1);
insert into t values(2,2);
insert into t values(3,4);
SELECT id
FROM t a
WHERE NOT EXISTS
( SELECT 1
FROM t b
WHERE b.eid = a.id );
or use NOT IN:
SELECT ID
FROM t
WHERE ID NOT IN
(SELECT EID
FROM t);
produces:
| id |
|----|
| 3 |
Try the below query
SELECT ID FROM table WHERE ID NOT IN(SELECT EID FROM table );
Finding duplicate numbers is easy:
select id, count() from sequence
group by id
having count() > 1;
In this case there are no duplicates, since I’m not concentrating on that in this post (finding duplicates is straightforward enough that I hope you can see how it’s done). I had to scratch my head for a second to find missing numbers in the sequence, though. Here is my first shot at it:
select l.id + 1 as start
from sequence as l
left outer join sequence as r on l.id + 1 = r.id
where r.id is null;
The idea is to exclusion join against the same sequence, but shifted by one position. Any number with an adjacent number will join successfully, and the WHERE clause will eliminate successful matches, leaving the missing numbers. Here is the result:
https://www.xaprb.com/blog/2005/12/06/find-missing-numbers-in-a-sequence-with-sql/
if you want a lighter way to search millions of rows of data,
I was try for search in more than 23 millions rows with old CPU (12.6Gb data need about 1gb of free ram):
Affected rows: 0 Found rows: 346.764 Warnings: 0 Duration for 2 queries: 00:04:48.0 (+ 2,656 sec. network)
SET #idBefore=0, #st=0,#diffSt=0,#diffEnd=0;
SELECT res.idBefore `betweenID`, res.ID `andNextID`
, res.startEID, res.endEID
, res.diff `diffEID`
-- DON'T USE this missingEIDfor more than a thousand of rows
-- this is just for sample view
, GROUP_CONCAT(b.aNum) `missingEID`
FROM (
SELECT
#idBefore `idBefore`
, #idBefore:=(a.id) `ID`
, #diffSt:=(#st) `startEID`
, #diffEnd:=(a.eid) `endEID`
, #st:=a.eid `end`
, #diffEnd-#diffSt-1 `diff`
FROM eid a
ORDER BY a.ID
) res
-- DON'T USE this integers for more than a thousand of rows
-- this is just for sample view
CROSS JOIN (SELECT a.ID + (b.ID * 10) + (c.ID * 100) AS aNum FROM integers a, integers b, integers c) b
WHERE res.diff>0 AND b.aNum BETWEEN res.startEID+1 AND res.endEID-1
GROUP BY res.ID;
check out this http://sqlfiddle.com/#!9/33deb3/9
and this is for missing ID http://sqlfiddle.com/#!9/3ea00c/9

Join two subqueries and have a field: division of the results of two subqueries

I have a table like this:
userid | trackid | path
123 70000 ad
123 NULL abc.com
123 NULL Apply
345 70001 Apply
345 70001 Apply
345 NULL Direct
345 NULL abc.com
345 NULL cdf.com
And I want a query like this. When path='abc.com', num_website +1; when path='Apply', num_apply +1
userid | num_website | num_Apply | num_website/num_Apply
123 1 1 1
345 1 2 0.5
My syntax looks like this:
select * from
(select userid,count(path) as is_CWS
from TABLE
where path='abc.com'
group by userid
having count(path)>1) a1
JOIN
(select userid,count(userid) as Apply_num from
where trackid is not NULL
group by userid) a2
on a1.userid=a2.userid
My question is
1. how to have the field num_website/num_apply in term of my syntax above?
2. is there any other easier way to get the result I want?
Any spots shared will appreciate.
The simplest way to do it would be to change the select line:
SELECT a1.userid, a1.is_CWS, a2.Apply_num, a1.is_CWS/a2.Apply_num FROM
(select userid,count(path) as is_CWS
from TABLE
where path='abc.com'
group by userid
having count(path)>1) a1
JOIN
(select userid,count(userid) as Apply_num
from TABLE
where trackid is not NULL
group by userid) a2
on a1.userid=a2.userid
and then continue with the rest of your query as you have it. The star means "select everything." If you wanted to select only a few things, you would just list those things in place of the star, and if you wanted to select some other values based on those things, you would put those in the stars as well. In this case a1.is_CWS/a2.Apply_num is an expression, and MySql knows how to evaluate it based on the values of a1.is_CWS and a2.Apply_num.
In the same vein, you can do a lot of what those subqueries are doing in a single expression instead of a subquery. objectNotFound has the right idea. Instead of doing a subquery to retrieve the number of rows with a certain attribute, you can select SUM(path="abc.com") as Apply_num and you don't have to join anymore. Making that change gives us:
SELECT a1.userid,
SUM(path="abc.com") as is_CWS,
a2.Apply_num,
is_CWS/a2.Apply_num FROM
TABLE
JOIN
(select userid,count(userid) as Apply_num
FROM TABLE
where trackid is not NULL
group by userid) a2
on a1.userid=a2.userid
GROUP BY userid
Notice I moved the GROUP BY to the end of the query. Also notice instead of referencing a1.is_CWS I now reference just is_CWS (it's no longer inside the a1 subtable so we can just reference it)
You can do the same thing to the other subquery then they can share the GROUP BY clause and you won't need the join anymore.
to get you started ... you can build on top of this :
select
userid,
SUM(CASE WHEN path='abc.com'then 1 else 0 end ) as num_website,
SUM(CASE WHEN path='Apply' and trackid is not NULL then 1 else 0 end ) as Apply_Num
from TABLE
WHERE path='abc.com' or path='Apply' -- may not need this ... play with it
group by userid

Mysql count with case when statement

Consider:
SELECT(count(c.id),
case when(count(c.id) = 0)
then 'loser'
when(count(c.id) BETWEEN 1 AND 4)
then 'almostaloser'
when(count(c.id) >= 5)
then 'notaloser'
end as status,
...
When all is said and done, the query as a whole produces a set of results that look similar to this:
Count | status
--------|-------------
2 | almostaloser //total count is between 2 and 4
--------|-------------
0 | loser // loser because total count = 0
--------|-------------
3 | almostaloser //again, total count between 2 and 4
--------|-------------
What I would like to achieve:
a method to reatain the information from the above table, but add a third column that will give a total count of each status, something like
select count(c.id)
case when(count(c.id) = 0 )
then loser as status AND count how many of the total count does this apply to
results would look similar to:
Count | status |total_of each status |
--------|-------------|---------------------|
2 | almostaloser| 2 |
--------|-------------|---------------------|
0 | loser | 1 |
--------|-------------|---------------------|
3 | almostaloser| 2 |
--------|-------------|----------------------
I've been told this could be achieved using a derived table, but i've not yet been able to get them both, only one or the other.
This can be achieved with this query (you must place your original query as subquery in two places):
SELECT t1.*, t2.total_of_each_status
FROM (
-- put here your query --
) t1
INNER JOIN (
SELECT status, count(*) AS total_of_each_status
FROM (
-- put here your query --
) t2
GROUP BY status
) t2 ON t2.status = t1.status

Deleting database existing record while asigning values from one row to other with unique values

EDIT2: Solved Thanks all for fast reply, appreciate ur help. Specially to Mr Jeremy Smyth for the working solution.
I'm fairly new to sql and cant find a solution to make an update query. I have the following table
Table: order
id | cid | pid
1 | 1 | a1
2 | 1 | a2
3 | 2 | a2
4 | 2 | a3
5 | 2 | a4
I want the cid of 2 to become 1, BUT not updating rows which have same pid i.e(id.2 & id.3).
The result i want is:
id | cid | pid
1 | 1 | a1
2 | 1 | a2
3 | 2 | a2
4 | '1' | a3
5 | '1' | a4
pseudo query example: UPDATE order SET cid=1 WHERE cid=2 AND 1.pid <> 2.pid;
EDIT1: not to confuse pid values with cid and id i changed them with 'a' in start. as suggested i'll not use order as table name.
On update I simply dont want duplicate pid for cid
Sorry for bad English.
I hope I understood you right:
UPDATE `order`
SET cid = 1
WHERE cid = 2
AND cid <> pid
What do you think?
Please notice: ORDER is a reserved word, read more.
I think you need something like this.
UPDATE order SET cid=1 WHERE cid=2 AND cid <> pid;
This can only be done in multiple steps (i.e. not a single UPDATE statement) in MySQL, because of the following points
Point 1: To get a list of rows that do not have the same pid as other rows, you would need to do a query before your update. For example:
SELECT id FROM `order`
WHERE pid NOT IN (
SELECT pid FROM `order`
GROUP BY pid
HAVING COUNT(*) > 1
)
That'll give you the list of IDs that don't share a pid with other rows. However we have to deal with Point 2, from http://dev.mysql.com/doc/refman/5.6/en/subquery-restrictions.html:
In general, you cannot modify a table and select from the same table in a subquery.
That means you can't use such a subquery in your UPDATE statement. You're going to have to use a staging table to store the pids and UPDATE based on that set.
For example, the following code creates a temporary table called badpids that contains all pids that appear multiple times in the orders table. Then, we execute the UPDATE, but only for rows that don't have a pid in the list of badpids:
CREATE TEMPORARY TABLE badpids (pid int);
INSERT INTO badpids
SELECT pid FROM `order`
GROUP BY pid
HAVING COUNT(*) > 1;
UPDATE `order` SET cid = 1
WHERE cid= 2
AND pid NOT IN (SELECT pid FROM badpids);