UPDATE statement using the same table in subquery - mysql

SELECT
vl1.phone_number,
vl1.first_name,
CONCAT(
SUBSTRING(
(
SELECT
vl2.phone_number
FROM
list as vl2
WHERE
vl2.phone_number LIKE CONCAT( SUBSTRING( vl1.phone_number FROM 1 FOR 3 ), "%" )
ORDER BY
RAND( )
LIMIT 1
)
FROM
1 FOR 6
),
FLOOR( RAND( ) * ( 8999 ) ) + 1000
) AS autogenNumber
FROM
list as vl1
LIMIT 1
The results I get are
phone_number | firstname | autogenNumber
The autogenNumber is generated by first searching for other numbers that share the first three digits. Then 6 digits from that number are picked and another 4 random digits are subsituted to the end.
The above sql query generates the autogen number exactly as I need it.
However, now the issue arises when I want to update the column security_phrase in this list using the similar query below.
UPDATE list as vl1
SET vl1.security_phrase = (
CONCAT(
SUBSTRING(
(
SELECT
vl2.phone_number
FROM
list AS vl2
WHERE
vl2.phone_number LIKE CONCAT( SUBSTRING(phone_number FROM 1 FOR 3 ), "%" )
ORDER BY
RAND( )
LIMIT 1
)
FROM
1 FOR 6
),
FLOOR( RAND( ) * ( 8999 ) ) + 1000
)
)
LIMIT 10
Gives me an error:
1093 - Table 'vl1' is specified twice, both as a target for 'UPDATE'
and as a separate source for data
I have also tried
UPDATE list AS vl1
JOIN list AS vl2
SET vl1.security_phrase = (
CONCAT( SUBSTRING( vl2.phone_number FROM 1 FOR 6 ), FLOOR( RAND( ) * ( 8999 ) ) + 1000 )
)
WHERE
vl2.phone_number LIKE CONCAT( SUBSTRING( vl1.phone_number FROM 1 FOR 3 ), "%" )
Not working and does not give the intended results...
Any help

MySQL does not allow referencing the table being updated again in another subquery, unless it is inside the FROM clause (Derived Table).
Now, in your particular case, we will need to put the complete SELECT query block as a Derived Table. As discussed in chat, lead_id is your Primary Key, so we will join back using the PK to update the rows accordingly.
UPDATE list AS t1
JOIN
(
SELECT
vl1.lead_id,
CONCAT(
SUBSTRING(
(
SELECT
vl2.phone_number
FROM
list as vl2
WHERE
vl2.phone_number LIKE CONCAT( SUBSTRING( vl1.phone_number FROM 1 FOR 3 ), "%" )
ORDER BY
RAND( )
LIMIT 1
)
FROM
1 FOR 6
),
FLOOR( RAND( ) * ( 8999 ) ) + 1000
) AS autogenNumber
FROM
list as vl1
) AS dt
ON dt.lead_id = t1.lead_id
SET t1.security_phrase = dt.autogenNumber

Related

mysql query to display all the enum values created for a column named department?

I have a basic table named employees, with the following columns:
user_id PK
first_name
last_name
department enum('accounts', 'sales', 'marketing', 'customer support','billing', 'logistics', 'production') NULL is default.
project_history
email
password SHA1
registration_date
So far ive created the database and it contains one table, 'employees'. As you can see from above its a very simple straight forward table.
I want a quick and easy to to run an sql query in phpMyAdmin's sql editor so I can easily see what enum values/options are available for department. I was intrigued as I wanted to remember what values were created, the only way I am able to see these is by going to structure in phpmyadmin.
Surely there is an sql query I can run to very quickly see the enum values set for department ?
If so I just wanted to know what it was.
There is no need to share the mysql database or the table users as its running locally under wampserver and you can go by what ive provided above.
I expect the query to return something similar to the below:
department
---------------
NULL - 0
accounts - 1
sales - 2
marketing - 3
customer support - 4
billing - 5
logistics - 6
production - 7
either way, i just want to see the enum values assigned to column department irrespective of how its shown. Can it be done via an sql query cos im very certain it can.
This answer is meant for educational purposes, as the
suggestion provived by JNevill in the comments above makes more sense to do
This is possible in pure MySQL code but you will have to write tricky SQL.
Part of the answer includes a SQL number generator
SELECT
(#number := #number + 1) AS number
FROM (
SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 UNION SELECT 10
) AS record_1
CROSS JOIN ( SELECT #number := 0 ) AS init_user_param
see demo
The other part is getting the enum as comma seperated string and knowing the number of items.
Query
SELECT
REPLACE(
REPLACE(
REPLACE(COLUMN_TYPE, 'enum(', '')
, ')'
, ''
)
, "'"
, ''
) AS comma_separated
, LENGTH(
REPLACE(
REPLACE(
REPLACE(COLUMN_TYPE, 'enum(', '')
, ')'
, ''
)
, "'"
, ''
)
) - LENGTH(REPLACE(
REPLACE(
REPLACE(
REPLACE(COLUMN_TYPE, 'enum(', '')
, ')'
, ''
)
, "'"
, ''
), ',', '')) + 1 AS number_of_items
FROM information_schema.COLUMNS
WHERE
TABLE_SCHEMA = DATABASE()
AND
TABLE_NAME = 'test'
AND
COLUMN_NAME = 'department'
see demo
The last part is knowing how to separate comma separated values..
SELECT
SUBSTRING_INDEX(
SUBSTRING_INDEX(
'accounts,sales,marketing,customer support,billing,logistics,production'
, ','
, 1)
,
','
, -1
)
see demo
When you look in the demo you notice a number which increments to get the next item. Now you know why i need to use a sql number generator.
All magic tricks (parts) combined
SELECT
number
, SUBSTRING_INDEX(
SUBSTRING_INDEX(comma_separated, ',', number), ',', -1)
FROM (
SELECT
(#number := #number + 1) AS number
FROM (
SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 UNION SELECT 10
) AS record_1
CROSS JOIN ( SELECT #number := 0 ) AS init_user_param
) AS sql_number_generator
CROSS JOIN (
SELECT
REPLACE(
REPLACE(
REPLACE(COLUMN_TYPE, 'enum(', '')
, ')'
, ''
)
, "'"
, ''
) AS comma_separated
, LENGTH(
REPLACE(
REPLACE(
REPLACE(COLUMN_TYPE, 'enum(', '')
, ')'
, ''
)
, "'"
, ''
)
) - LENGTH(REPLACE(
REPLACE(
REPLACE(
REPLACE(COLUMN_TYPE, 'enum(', '')
, ')'
, ''
)
, "'"
, ''
), ',', '')) + 1 AS number_of_items
FROM information_schema.COLUMNS
WHERE
TABLE_SCHEMA = DATABASE()
AND
TABLE_NAME = 'test'
AND
COLUMN_NAME = 'department'
) AS a
WHERE
number BETWEEN 0 AND number_of_items
Result
| number | SUBSTRING_INDEX(
SUBSTRING_INDEX(comma_separated, ',', number), ',', -1) |
| ------ | --------------------------------------------------------------------------- |
| 1 | accounts |
| 2 | sales |
| 3 | marketing |
| 4 | customer support |
| 5 | billing |
| 6 | logistics |
| 7 | production |
see demo
Performance might be different between MySQL versions and or if the MySQL version caches the information_schema.COLUMNS in memory or optimisations exists to access information_schema .. Also performance depends offcource off the number of existing columns on the complete server.

MySQL - Select rows where a given character is repetable for x times

I need to create a select statement in this way:
SELECT * FROM mytable where COUNT_CHARACTER('-', mycolumn) = 2
It select all rows where the character '-' is present exactly two times in all records.
Is there a function in MySQL as this COUNT_CHARACTER?
This may play trick
SELECT * FROM mytable
WHERE (LENGTH(mycolumn) - LENGTH(REPLACE(mycolumn, '-', '')))=2;
This expression usually does the trick.
LENGTH(MyField) - LENGTH( REPLACE ( MyField , '-', '') )
...
SELECT
(
SELECT
MyField,
FoundCount = LENGTH(MyField) - LENGTH( REPLACE ( MyField , '-', '') )
FROM
MyTable
)AS X
WHERE
FoundCount>2

(Newbie) MySQL View

I'm new to SQL and probably going about this the wrong way but could you help?
I need to create a VIEW in MySQL but I can't figure out how to combine these two SQL statements, as VIEWs do not accept multiple SELECTS or Variables.
NB: the second statement works perfectly when replacing the #numberOfGames var with the correct number (manually calculated).
First statement - to return the total number of games for year:
SELECT COUNT( id ) INTO #numberOfGames FROM tblgames WHERE gdate LIKE '2014%';
Second statement - to create VIEW data:
SELECT
p.player AS player,
COUNT( c.gid ) AS gameCount,
SUM( c.cash ) AS cash,
ROUND( AVG( c.cash ), 2 ) AS avg,
SUM( ( CASE WHEN ( c.wotn > 0 ) THEN c.wotn ELSE 0 END ) ) AS wotn,
SUM( ( CASE WHEN ( c.cash > 0 ) THEN c.cash ELSE 0 END ) ) AS cashWon,
SUM( ( CASE WHEN ( c.cash < 0 ) THEN c.cash ELSE 0 END ) ) AS cashLost,
ROUND( AVG( ( CASE WHEN ( c.cash >= 0 ) THEN c.cash END ) ),2 ) AS avgWin,
ROUND( AVG( ( CASE WHEN ( c.cash < 0 ) THEN c.cash END ) ),2 ) AS avgLoss,
IF(
( ( COUNT( c.pid ) > ( #numberOfGames / 3 ) ) AND ( COUNT( c.pid ) > 2 ) ),
ROUND( ( ( AVG( c.cash ) * 10 ) + 200 ), 2 ),
ROUND( AVG( c.cash ), 2 )
) AS sortingPoints
FROM tblplayers p
LEFT JOIN tblcash c ON p.id = c.pid
LEFT JOIN tblgames g ON g.id = c.gid
WHERE c.cash IS NOT NULL AND g.gdate LIKE '2014%'
GROUP BY c.pid
ORDER BY sortingPoints DESC;
I'm using the #numberOfGames vars for a simple maths equation that checks it a player has played more than a third of the total games in the year.
I hope someone can help point me it the right direction.
You are missing the point of what a view does.
You can't save multiple statements in one view. It's like trying to save two tables in one table. It's not possible.
What you need to do is, run your first Select, exactly as you have it. Save it as a view. Then you can use that result set as if it were any other live table, and join it to other tables in subsequent Select statements.

creating sql query for selecting multiple data

i need a sql query for my table tbl1
sample contents of the table like this
serial ida idb
1 1 2
2 1 3
3 3 7
4 3 6
5 2 4
6 2 6
.
in the table tbl1 column ida and idb are related like 1 is related with 2 and 3 , 2 is related with 4 and 6
ida value 1 s related data is 2 and 3 and i want to select the related data of 1' s related data (2 and 3).
2 and 3 s related data is 7, 6 and 4, 6. so the output will be (7,6,4)
. i need a sql query to display this out put. can anyone share some idea how to do that ..
SELECT DISTINCT idb FROM tbl1 WHERE ida = 2 OR ida = 3;
Is this what you were looking for?
EDIT: Corrected determining child branches of the hierarchy.
This may be of some use:
-- Sample data.
declare #Table as table ( serial int identity, ida int, idb int )
insert into #Table ( ida, idb ) values
( 1, 2 ), ( 1, 3 ),
( 3, 7 ), ( 3, 6 ),
( 2, 4 ), ( 2, 6 )
select * from #Table
-- Demonstrate recursive query.
; with CTE as (
-- Start with ida = 1.
select serial, ida, idb, 1 as depth, path = cast( right( '000000' + cast( ida as varchar(6) ), 6 ) as varchar(1024) )
from #Table
where ida = 1
union all
-- Add each row related to the most recent selected row(s).
select T.serial, T.ida, T.idb, C.depth + 1, cast( C.path + right( '000000' + cast( T.ida as varchar(6) ), 6 ) as varchar(1024) )
from CTE as C inner join
#Table as T on T.ida = C.idb
)
-- Show everything.
select *
from CTE
-- Repeat the recursive query.
; with CTE as (
-- Start with ida = 1.
select serial, ida, idb, 1 as depth, path = cast( right( '000000' + cast( ida as varchar(6) ), 6 ) as varchar(1024) )
from #Table
where ida = 1
union all
-- Add each row related to the most recent selected row(s).
select T.serial, T.ida, T.idb, C.depth + 1, cast( C.path + right( '000000' + cast( T.ida as varchar(6) ), 6 ) as varchar(1024) )
from CTE as C inner join
#Table as T on T.ida = C.idb
)
-- Select only the deepest children.
select distinct idb
from CTE as C
where not exists ( select 42 from CTE where left( path, len( C.path ) ) = C.path and len( path ) > len( C.path ))
order by idb
Left as an exercise is pivoting the result.
select distinct idb from tbl1 where ida in (select idb from tbl1 where ida = 1)

mysql rename results?

I have this function
SELECT LEFT( eventName, INSTR( CONCAT( eventName, ':' ) , ':' ) ) AS prefix, COUNT( * )
FROM trackingevent
GROUP BY LEFT( eventName, INSTR( CONCAT( eventName, ':' ) , ':' ) )
UNION SELECT homeupload, COUNT( * )
FROM link
GROUP BY homeupload
UNION
SELECT mediaType, COUNT( * )
FROM link
GROUP BY mediaType
UNION
SELECT emailSub, COUNT(*) FROM link WHERE emailSub='1' GROUP BY emailSub
and it generates something like
prefix COUNT(*)
CONTEST_ENTRY: 4
EMAIL_SHARE 77
FLICKR_SHARE 9
SHARE_FACEBOOK 105
SHARE_STATION_LOGIN 223
TWEET_SHARE 18
0 320
1 1
image 320
video 1
1 195
I want to rename the 0,1 and the other 1 to something else. Maybe homeupload, onsite, or something.
The first 0 and 1 are UNION SELECT homeupload, COUNT( * )
FROM link
GROUP BY homeupload
As there are two values
The second 1 is UNION
SELECT emailSub, COUNT(*) FROM link WHERE emailSub='1' GROUP BY emailSub
How can I rename the results?
in short, using IF
...
UNION
SELECT IF(homeupload = 0,
"someStringDescribingStatus0",
"someStringDescribingStatus1") as homeUploadStatus,
count(*)
FROM ...