Using the "With Clause" SQL Server 2008 - sql-server-2008

Can someone show me a sample SQL server script that I can look at that uses the "With Clause"?
I am trying to use this clause to iterate through 200 databases that contain the same table that I am trying to run a query on. I am trying to avoid using a cursor because the query time takes too long as well as using a while a loop.
Can someone advise me as to what I can do.
Thank you.

Just a poke, but here's another way to write FizzBuzz :)
100 rows is enough to show the WITH statement, I reckon.
;WITH t100 AS (
SELECT n=number
FROM master..spt_values
WHERE type='P' and number between 1 and 100
)
SELECT
ISNULL(NULLIF(
CASE WHEN n % 3 = 0 THEN 'Fizz' Else '' END +
CASE WHEN n % 5 = 0 THEN 'Buzz' Else '' END, ''), RIGHT(n,3))
FROM t100
But the real power behind WITH (known as Common Table Expression http://msdn.microsoft.com/en-us/library/ms190766.aspx "CTE") in SQL Server 2005 and above is the Recursion, as below where the table is built up through iterations adding to the virtual-table each time.
;WITH t100 AS (
SELECT n=1
union all
SELECT n+1
FROM t100
WHERE n < 100
)
SELECT
ISNULL(NULLIF(
CASE WHEN n % 3 = 0 THEN 'Fizz' Else '' END +
CASE WHEN n % 5 = 0 THEN 'Buzz' Else '' END, ''), RIGHT(n,3))
FROM t100
To run a similar query in all database, you can use the undocumented sp_msforeachdb. It has been mentioned in another answer, but it is sp_msforeachdb, not sp_foreachdb.
Be careful when using it though, as some things are not what you expect. Consider this example
exec sp_msforeachdb 'select count(*) from sys.objects'
Instead of the counts of objects within each DB, you will get the SAME count reported, begin that of the current DB.
To get around this, always "use" the database first. Note the square brackets to qualify multi-word database names.
exec sp_msforeachdb 'use [?]; select count(*) from sys.objects'
For your specific query about populating a tally table, you can use something like the below. Not sure about the DATE column, so this tally table has only the DBNAME and IMG_COUNT columns, but hope it helps you.
create table #tbl (dbname sysname, img_count int);
exec sp_msforeachdb '
use [?];
if object_id(''tbldoc'') is not null
insert #tbl
select ''?'', count(*) from tbldoc'
select * from #tbl

There are two types of WITH clauses:
Here is the FizzBuzz in SQL form, using a WITH common table expression (CTE).
;WITH mil AS (
SELECT TOP 1000000 ROW_NUMBER() OVER ( ORDER BY c.column_id ) [n]
FROM master.sys.all_columns as c
CROSS JOIN master.sys.all_columns as c2
)
SELECT CASE WHEN n % 3 = 0 THEN
CASE WHEN n % 5 = 0 THEN 'FizzBuzz' ELSE 'Fizz' END
WHEN n % 5 = 0 THEN 'Buzz'
ELSE CAST(n AS char(6))
END + CHAR(13)
FROM mil
Here is a select statement also using a WITH clause
SELECT * FROM orders WITH (NOLOCK) where order_id = 123

Try the sp_foreachdb procedure.

Related

Optimizing Parameterized MySQL Queries

I have a query that has a number of parameters which if I run from in MySQLWorkbench takes around a second to run.
If I take this query and get rid of the parameters and instead substitute the values into the query then it takes about 22 seconds to run, same as If I convert this query to a parameterized stored procedure and run it (it then takes about 22 seconds).
I've enabled profiling on MySQL and I can see a few things there. For example, it shows the number of rows examined and there's an order of difference (20,000 to 400,000) which I assume is the reason for the 20x increase in processing time.
The other difference in the profile is that the parameterized query sent from MySQLWorkbench still has the parameters in (e.g. where limit < #lim) while the sproc the values have been set (where limit < 300).
I've tried this a number of different ways, I'm using JetBrains's DataGrip (as well as MySQLWorkbench) and that works like MySQLWorkbench (sends through the # parameters), I've tried executing the queries and the sproc from MySQLWorkbench, DataGrip, Java (JDBC) and .Net. I've also tried prepared statements in Java but I can't get anywhere near the performance of sending the 'raw' SQL to MySQL.
I feel like I'm missing something obvious here but I don't know what it is.
The query is relatively complex, it has a CTE a couple of sub-selects and a couple of joins, but as I said it runs quickly straight from MySQL.
My main question is why the query is 20x faster in one format than another.
Does the way the query is sent to MySQL have anything to do with this (the '#' values sent through and can I replicate this in a stored procedure?
Updated 1st Jan
Thanks for the comments, I didn't post the query originally as I'm more interested in the general concepts around the use of variables/parameters and how I could take advantage of that (or not)
Here is the original query:
with tmp_bat as (select bd.MatchId,
bd.matchtype,
bd.playerid,
bd.teamid,
bd.opponentsid,
bd.inningsnumber,
bd.dismissal,
bd.dismissaltype,
bd.bowlerid,
bd.fielderid,
bd.score,
bd.position,
bd.notout,
bd.balls,
bd.minutes,
bd.fours,
bd.sixes,
bd.hundred,
bd.fifty,
bd.duck,
bd.captain,
bd.wicketkeeper,
m.hometeamid,
m.awayteamid,
m.matchdesignator,
m.matchtitle,
m.location,
m.tossteamid,
m.resultstring,
m.whowonid,
m.howmuch,
m.victorytype,
m.duration,
m.ballsperover,
m.daynight,
m.LocationId
from (select *
from battingdetails
where matchid in
(select id
from matches
where id in (select matchid from battingdetails)
and matchtype = #match_type
)) as bd
join matches m on m.id = bd.matchid
join extramatchdetails emd1
on emd1.MatchId = m.Id
and emd1.TeamId = bd.TeamId
join extramatchdetails emd2
on emd2.MatchId = m.Id
and emd2.TeamId = bd.TeamId
)
select players.fullname name,
teams.teams team,
'' opponents,
players.sortnamepart,
innings.matches,
innings.innings,
innings.notouts,
innings.runs,
HS.score highestscore,
HS.NotOut,
CAST(TRUNCATE(innings.runs / (CAST((Innings.Innings - innings.notOuts) AS DECIMAL)),
2) AS DECIMAL(7, 2)) 'Avg',
innings.hundreds,
innings.fifties,
innings.ducks,
innings.fours,
innings.sixes,
innings.balls,
CONCAT(grounds.CountryName, ' - ', grounds.KnownAs) Ground,
'' Year,
'' CountryName
from (select count(case when inningsnumber = 1 then 1 end) matches,
count(case when dismissaltype != 11 and dismissaltype != 14 then 1 end) innings,
LocationId,
playerid,
MatchType,
SUM(score) runs,
SUM(notout) notouts,
SUM(hundred) Hundreds,
SUM(fifty) Fifties,
SUM(duck) Ducks,
SUM(fours) Fours,
SUM(sixes) Sixes,
SUM(balls) Balls
from tmp_bat
group by MatchType, playerid, LocationId) as innings
JOIN players ON players.id = innings.playerid
join grounds on Grounds.GroundId = LocationId and grounds.MatchType = innings.MatchType
join
(select pt.playerid, t.matchtype, GROUP_CONCAT(t.name SEPARATOR ', ') as teams
from playersteams pt
join teams t on pt.teamid = t.id
group by pt.playerid, t.matchtype)
as teams on teams.playerid = innings.playerid and teams.matchtype = innings.MatchType
JOIN
(SELECT playerid,
LocationId,
MAX(Score) Score,
MAX(NotOut) NotOut
FROM (SELECT battingdetails.playerid,
battingdetails.score,
battingdetails.notout,
battingdetails.LocationId
FROM tmp_bat as battingdetails
JOIN (SELECT battingdetails.playerid,
battingdetails.LocationId,
MAX(battingdetails.Score) AS score
FROM tmp_bat as battingdetails
GROUP BY battingdetails.playerid,
battingdetails.LocationId,
battingdetails.playerid) AS maxscore
ON battingdetails.score = maxscore.score
AND battingdetails.playerid = maxscore.playerid
AND battingdetails.LocationId = maxscore.LocationId ) AS internal
GROUP BY internal.playerid, internal.LocationId) AS HS
ON HS.playerid = innings.playerid and hs.LocationId = innings.LocationId
where innings.runs >= #runs_limit
order by runs desc, KnownAs, SortNamePart
limit 0, 300;
Wherever you see '#match_type' then I substitute that for a value ('t'). This query takes ~1.1 secs to run. The query with the hard coded values rather than the variables down to ~3.5 secs (see the other note below). The EXPLAIN for this query gives this:
1,PRIMARY,<derived7>,,ALL,,,,,219291,100,Using temporary; Using filesort
1,PRIMARY,players,,eq_ref,PRIMARY,PRIMARY,4,teams.playerid,1,100,
1,PRIMARY,<derived2>,,ref,<auto_key3>,<auto_key3>,26,"teams.playerid,teams.matchtype",11,100,Using where
1,PRIMARY,grounds,,ref,GroundId,GroundId,4,innings.LocationId,1,10,Using where
1,PRIMARY,<derived8>,,ref,<auto_key0>,<auto_key0>,8,"teams.playerid,innings.LocationId",169,100,
8,DERIVED,<derived3>,,ALL,,,,,349893,100,Using temporary
8,DERIVED,<derived14>,,ref,<auto_key0>,<auto_key0>,13,"battingdetails.PlayerId,battingdetails.LocationId,battingdetails.Score",10,100,Using index
14,DERIVED,<derived3>,,ALL,,,,,349893,100,Using temporary
7,DERIVED,t,,ALL,PRIMARY,,,,3323,100,Using temporary; Using filesort
7,DERIVED,pt,,ref,TeamId,TeamId,4,t.Id,65,100,
2,DERIVED,<derived3>,,ALL,,,,,349893,100,Using temporary
3,DERIVED,matches,,ALL,PRIMARY,,,,114162,10,Using where
3,DERIVED,m,,eq_ref,PRIMARY,PRIMARY,4,matches.Id,1,100,
3,DERIVED,emd1,,ref,"PRIMARY,TeamId",PRIMARY,4,matches.Id,1,100,Using index
3,DERIVED,emd2,,eq_ref,"PRIMARY,TeamId",PRIMARY,8,"matches.Id,emd1.TeamId",1,100,Using index
3,DERIVED,battingdetails,,ref,"TeamId,MatchId,match_team",match_team,8,"emd1.TeamId,matches.Id",15,100,
3,DERIVED,battingdetails,,ref,MatchId,MatchId,4,matches.Id,31,100,Using index; FirstMatch(battingdetails)
and the EXPLAIN for the query with the hardcoded values looks like this:
1,PRIMARY,<derived8>,,ALL,,,,,20097,100,Using temporary; Using filesort
1,PRIMARY,players,,eq_ref,PRIMARY,PRIMARY,4,HS.PlayerId,1,100,
1,PRIMARY,grounds,,ref,GroundId,GroundId,4,HS.LocationId,1,100,Using where
1,PRIMARY,<derived2>,,ref,<auto_key0>,<auto_key0>,30,"HS.LocationId,HS.PlayerId,grounds.MatchType",17,100,Using where
1,PRIMARY,<derived7>,,ref,<auto_key0>,<auto_key0>,46,"HS.PlayerId,innings.MatchType",10,100,Using where
8,DERIVED,matches,,ALL,PRIMARY,,,,114162,10,Using where; Using temporary
8,DERIVED,m,,eq_ref,"PRIMARY,LocationId",PRIMARY,4,matches.Id,1,100,
8,DERIVED,emd1,,ref,"PRIMARY,TeamId",PRIMARY,4,matches.Id,1,100,Using index
8,DERIVED,emd2,,eq_ref,"PRIMARY,TeamId",PRIMARY,8,"matches.Id,emd1.TeamId",1,100,Using index
8,DERIVED,<derived14>,,ref,<auto_key2>,<auto_key2>,4,m.LocationId,17,100,
8,DERIVED,battingdetails,,ref,"PlayerId,TeamId,Score,MatchId,match_team",MatchId,8,"matches.Id,maxscore.PlayerId",1,3.56,Using where
8,DERIVED,battingdetails,,ref,MatchId,MatchId,4,matches.Id,31,100,Using index; FirstMatch(battingdetails)
14,DERIVED,matches,,ALL,PRIMARY,,,,114162,10,Using where; Using temporary
14,DERIVED,m,,eq_ref,PRIMARY,PRIMARY,4,matches.Id,1,100,
14,DERIVED,emd1,,ref,"PRIMARY,TeamId",PRIMARY,4,matches.Id,1,100,Using index
14,DERIVED,emd2,,eq_ref,"PRIMARY,TeamId",PRIMARY,8,"matches.Id,emd1.TeamId",1,100,Using index
14,DERIVED,battingdetails,,ref,"TeamId,MatchId,match_team",match_team,8,"emd1.TeamId,matches.Id",15,100,
14,DERIVED,battingdetails,,ref,MatchId,MatchId,4,matches.Id,31,100,Using index; FirstMatch(battingdetails)
7,DERIVED,t,,ALL,PRIMARY,,,,3323,100,Using temporary; Using filesort
7,DERIVED,pt,,ref,TeamId,TeamId,4,t.Id,65,100,
2,DERIVED,matches,,ALL,PRIMARY,,,,114162,10,Using where; Using temporary
2,DERIVED,m,,eq_ref,PRIMARY,PRIMARY,4,matches.Id,1,100,
2,DERIVED,emd1,,ref,"PRIMARY,TeamId",PRIMARY,4,matches.Id,1,100,Using index
2,DERIVED,emd2,,eq_ref,"PRIMARY,TeamId",PRIMARY,8,"matches.Id,emd1.TeamId",1,100,Using index
2,DERIVED,battingdetails,,ref,"TeamId,MatchId,match_team",match_team,8,"emd1.TeamId,matches.Id",15,100,
2,DERIVED,battingdetails,,ref,MatchId,MatchId,4,matches.Id,31,100,Using index; FirstMatch(battingdetails)
Pointers as to ways to improve my SQL are always welcome (I'm definitely not a database person), but I''d still like to understand whether I can use the SQL with the variables from code and why that improves the performance by so much
Update 2 1st Jan
AAArrrggghhh. My machine rebooted overnight and now the queries are generally running much quicker. It's still 1 sec vs 3 secs but the 20 times slowdown does seem to have disappeared
In your WITH construct, are you overthinking your select in ( select in ( select in ))) ... overstating what could just be simplified to the with Innings I have in my solution.
Also, you were joining to the extraMatchDetails TWICE, but joined on the same conditions on match and team, but never utliized either of those tables in the "WITH CTE" rendering that component useless, doesn't it? However, the MATCH table has homeTeamID and AwayTeamID which is what I THINK your actual intent was
Also, your WITH CTE is pulling many columns not needed or used in subsequent return such as Captain, WicketKeeper.
So, I have restructured... pre-query the batting details once up front and summarized, then you should be able to join off that.
Hopefully this MIGHT be a better fit, function and performance for your needs.
with innings as
(
select
bd.matchId,
bd.matchtype,
bd.playerid,
m.locationId,
count(case when bd.inningsnumber = 1 then 1 end) matches,
count(case when bd.dismissaltype in ( 11, 14 ) then 0 else 1 end) innings,
SUM(bd.score) runs,
SUM(bd.notout) notouts,
SUM(bd.hundred) Hundreds,
SUM(bd.fifty) Fifties,
SUM(bd.duck) Ducks,
SUM(bd.fours) Fours,
SUM(bd.sixes) Sixes,
SUM(bd.balls) Balls
from
battingDetails bd
join Match m
on bd.MatchID = m.MatchID
where
matchtype = #match_type
group by
bd.matchId,
bd.matchType,
bd.playerid,
m.locationId
)
select
p.fullname playerFullName,
p.sortnamepart,
CONCAT(g.CountryName, ' - ', g.KnownAs) Ground,
t.team,
i.matches,
i.innings,
i.runs,
i.notouts,
i.hundreds,
i.fifties,
i.ducks,
i.fours,
i.sixes,
i.balls,
CAST( TRUNCATE( i.runs / (CAST((i.Innings - i.notOuts) AS DECIMAL)), 2) AS DECIMAL(7, 2)) 'Avg',
hs.maxScore,
hs.maxNotOut,
'' opponents,
'' Year,
'' CountryName
from
innings i
JOIN players p
ON i.playerid = p.id
join grounds g
on i.locationId = g.GroundId
and i.matchType = g.matchType
join
(select
pt.playerid,
t.matchtype,
GROUP_CONCAT(t.name SEPARATOR ', ') team
from
playersteams pt
join teams t
on pt.teamid = t.id
group by
pt.playerid,
t.matchtype) as t
on i.playerid = t.playerid
and i.MatchType = t.matchtype
join
( select
i2.playerid,
i2.locationid,
max( i2.score ) maxScore,
max( i2.notOut ) maxNotOut
from
innings i2
group by
i2.playerid,
i2.LocationId ) HS
on i.playerid = HS.playerid
AND i.locationid = HS.locationid
FROM
where
i.runs >= #runs_limit
order by
i.runs desc,
g.KnownAs,
p.SortNamePart
limit
0, 300;
Now, I know that you stated that after the server reboot, performance is better, but really, what you DO have appears to really have overbloated queries.
Not sure this is the correct answer but I thought I'd post this in case other people have the same issue.
The issue seems to be the use of CTEs in a stored procedure. I have a query that creates a CTE and then uses that CTE 8 times. If I run this query using interpolated variables it takes about 0.8 sec, if I turn it into a stored procedure and use the stored procedure parameters then it takes about to a minute (between 45 and 63 seconds) to run!
I've found a couple of ways of fixing this, one is to use multiple temporary tables (8 in this case) as MySQL cannot re-use a temp table in a query. This gets the query time right down but just doesn't fell like a maintainable or scalable solution. The other fix is to leave the variables in place and assign them from the stored procedure parameters, this also has no real performance issues. So my sproc looks like this:
create procedure bowling_individual_career_records_by_year_for_team_vs_opponent(IN team_id INT,
IN opponents_id INT)
begin
set #team_id = team_id;
set #opponents_id = opponents_id;
# use these variables in the SQL below
...
end
Not sure this is the best solution but it works for me and keeps the structure of the SQL the same as it was previously.

how to know the source table from a complex sql query

PFB the query in which I want know the actual table where I can find these (pin_ein,engineer_pin,transaction_date,EFFECTIVE_WEEK )....
select count(1),pin_ein,engineer_pin,transaction_date,EFFECTIVE_WEEK from
(SELECT vw1.pin_ein, vw1.engineer_pin,
vw1.transaction_date, vw1.effective_week,
vw1.stores_tools_cost,
(vw1.stores_total_cost - vw1.stores_tools_cost
) stores_total_cost_excl_tools,
vw1.item_count, vw1.stores_visit_count,
CASE
WHEN vw1.stores_total_cost <
5
THEN vw1.stores_visit_count
END stores_low_cost_visit_count,
vw1.actual_ouc ouc, er.eng_name engineer_name,
CASE
WHEN c.home_parked IS NOT NULL
THEN c.home_parked
ELSE 'N'
END home_parker,
CASE
WHEN c.home_parked IS NOT NULL
THEN c.commute_time
ELSE -99
END commute_time,
vw1.stores_com_cost ---v9.3---
FROM (SELECT pin_ein, engineer_pin, actual_ouc,
transaction_date, effective_week,
NVL
(SUM
(CASE
WHEN ( cow LIKE '%TOOL%'
OR cow LIKE
'%TOOLE%'
)
THEN transaction_value
END
),
0
) stores_tools_cost,
SUM
(transaction_value
) stores_total_cost,
SUM (transaction_quantity)
item_count,
COUNT
(DISTINCT sta_code
) stores_visit_count,
NVL
(SUM
(CASE
WHEN cow in (SELECT cow FROM orbit_odw.stores_cow_ref)
THEN transaction_value
END
),
0
) stores_com_cost ---v9.3---
FROM orbit_odw.stores_transaction_dtls
WHERE effective_week BETWEEN 201543
AND 201610
/***Ver 6.0---last 13 weeks data to be considered***/
AND transaction_date
BETWEEN to_date('19-10-2015','dd-mm-yyyy')
AND to_date('06-03-2016','dd-mm-yyyy')
/***Ver 6.0---last 13 weeks data to be considered***/
GROUP BY pin_ein,
engineer_pin,
actual_ouc,
transaction_date,
effective_week) vw1,
(SELECT *
FROM orbit_odw.dim_wms_rmdm
WHERE current_status = 1) er,
(SELECT engineer_ein, commute_time,
home_parked
FROM orbit_odw.eng_parking_at_home_dtls
WHERE rec_end_date > SYSDATE
AND home_parked = 'Y') c
WHERE TO_CHAR (vw1.pin_ein) = er.ein
AND vw1.pin_ein = c.engineer_ein(+)) group by pin_ein,engineer_pin,transaction_date,EFFECTIVE_WEEK having count(1)>1;
Please help..
thanks in advance
Basically if i understand your problem correctly. You need to understand from where your outer SELECT is fetching data. So there is a simple rule set used to get these data. Steps are as follows.
Check the column output i.e in your case it's
pin_ein,engineer_pin,transaction_date,EFFECTIVE_WEEK
Check the inline view or table from which your outer query is
fetching the data. In your case its the only inline view you have
used --> So bit easy to identify :P
Now to identify how your inline view VW1 is populating data. In your
case table orbit_odw.stores_transaction_dtls is used to populate the
required fields.
Hope this much information is required. Also for simple queries you can always go to ALL_TAB_COLUMNS system tables to identify a table's column easily.

UNNEST function in MYSQL like POSTGRESQL

Is there a function like "unnest" from POSTGRESQL on MYSQL?
Query (PSQL):
select unnest('{1,2,3,4}'::int[])
Result (as table):
int |
_____|
1 |
_____|
2 |
_____|
3 |
_____|
4 |
_____|
Short answer
Yes, it is possible. From technical viewpoint, you can achieve that with one query. But the thing is - most probably, you are trying to pass some logic from application to data storage. Data storage is intended to store data, not to represent/format it or, even more, apply some logic to it.
Yes, MySQL doesn't have arrays data type, but in most cases it won't be a problem and architecture can be created so it will fit those limitations. And in any case, even if you'll achieve it somehow (like - see below) - you won't be possible to properly work later with that data, since it will be just result set. You may store it, of course - so to, let's say, index later, but then it's again a task for an application - so to create that import.
Also, make sure that it is not a Jaywalker case, so not about storing delimiter-separated values and later trying to extract them.
Long answer
From technical viewpoint, you can do it with Cartesian product of the two row sets. Then use a well known formula:
N = d1x101 + d2x102 + ...
Thus, you'll be able to create a "all-numbers" table and later iterate through it. That iteration, together with MySQL string functions, may lead you to something like this:
SELECT
data
FROM (
SELECT
#next:=LOCATE(#separator,#search, #current+1) AS next,
SUBSTR(SUBSTR(#search, #current, #next-#current), #length+1) AS data,
#next:=IF(#next, #next, NULL) AS marker,
#current:=#next AS current
FROM
(SELECT 0 as i UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) as n1
CROSS JOIN
(SELECT 0 as i UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) as n2
CROSS JOIN
(SELECT
-- set your separator here:
#separator := ',',
-- set your string here:
#data := '1,25,42,71',
-- and do not touch here:
#current := 1,
#search := CONCAT(#separator, #data, #separator),
#length := CHAR_LENGTH(#separator)) AS init
) AS joins
WHERE
marker IS NOT NULL
The corresponding fiddle would be here.
You should also notice: this is not a function. And with functions (I mean, user-defined with CREATE FUNCTION statement) it's impossible to get result row set since function in MySQL can not return result set by definition. However, it's not true to say that it's completely impossible to perform requested transformation with MySQL.
But remember: if you are able to do something, that doesn't mean you should do it.
This sample fetchs all "catchwords" from Table data, wich are seperated by ","
Maximum values in the commaseparated list is 100
WITH RECURSIVE num (n) AS (
SELECT 1
UNION ALL
SELECT n+1 FROM num WHERE n<100 -- change this, if more than 100 elements
)
SELECT DISTINCT substring_index(substring_index(catchwords, ',', n), ',', -1) as value
FROM data
JOIN num
ON char_length(catchwords) - char_length(replace(catchwords, ',', '')) >= n - 1
In newer Version of MySQL/MariaDB you can use JSON_TABLE if you can JOIN the elements:
SELECT cat.catchword, dat.*
FROM data dat
CROSS JOIN json_table(concat('[',dat.catchwords, ']')
, '$[*]' COLUMNS(
catchword VARCHAR(50) PATH '$'
)
) AS words

MySql, Without loop filling a table with semi/random data

How to have this code/output in MySql:
Had a recursive cte in MSSQL to fill a table with random data without loop e.g begin/end. Searched for similar logic in MySql but most or all solutions were using begin/end or for loops. Wonder if you could suggest a solution without loop in MySql.
Thanks
--MSSQL cte:------------------------------------
with t1( idi,val ) as
(
select
idi=1
,val=cast( 1 as real)
union all
select
idi=idi+1
,val=cast(val+rand() as real)
from t1
where idi<5
)
select idi,val from t1
-----------------------------------------------
Output in MSSQL:( semi random values)
idi | val
-------------
1 | 1
2 | 1.11
3 | 1.23
4 | 1.35
5 | 1.46
Edit:
Regarding discussions which considers set based codes as loop based codes indeed, I could understand this but just out of interest gave it a try in MSSQL 2008r2, here is the result:
1- above code with 32000 recursion took 2.812 sec
2- above output created with WHILE BEGIN END loop for 32000 took 53.640 sec
Obviously this is a big difference in execution time.
Here is the loop based code:
insert into #t1(idi,val)
select
idi=1
,val=1
declare #ii int = 2
while #ii<32000
begin
insert into #t1(idi,val)
select
idi=idi+1
,val=val+rand()
from #t1
where idi=#ii-1
set #ii=#ii+1
end
select * from #t1
MySql doesn't support CTE.
You need a procedure or some tricky queries like this one:
set #id=0;
set #val=0;
SELECT #id:=#id+1 As id,
#val:=#val+rand() As val
FROM information_schema.tables x
CROSS JOIN information_schema.tables y
LIMIT 10

Adding another value below the row

Hey guys i have did some coding in mysql to add a new line value to a row..
SELECT
babe
FROM
(SELECT
concat_ws(' ', 'assword \n') AS babe,
) test;
When i did like this i get an output like
BABE
assword name
What i need is an output like
BABE
assword
name(this would be below assword)
Is there any mysql functions to do this ??...or can i UPDATE the row ??..
I am a newbie in mysql. Hope you guys can help me out..Thanks in advance..
The statement includes a newline character in the babe column. You can confirm this by using the HEX() function to view the character encodings.
For example:
SELECT HEX(t.babe)
FROM ( SELECT CONCAT_WS(' ', 'assword \n') AS babe ) t
On my system, that Will output:
617373776F7264200A
It's easy enough to understand what was returned
a s s w o r d \n
61 73 73 77 6F 72 64 20 0A
(In the original query, there's an extraneous comma that will prevent the statement from running. Perhaps there was another expression in the SELECT list of the inline view, and that was returning the 'name' value that's shown in the example output. But we don't see any reference to that in the outer query.
It's not clear why you need the newline character. If you want to return:
BABE
-----------
asssword
name
That looks like two separate rows to me. But it's valid (but peculiar) to do this:
SELECT t.babe
FROM ( SELECT CONCAT_WS(' ', 'assword \nname') AS babe ) t
FOLLOWUP
Q: i just wanted to know how to add a new row below the assword ..if u know please edit the answer
It's not clear what result you are trying to achieve. The specification, divorced from the context of a use-case, is just bizarre.
A: If I had a need to return two rows: one row with the literal 'assword' and another row "below" it with the literal 'name', I could do this:
( SELECT 'assword' AS some_string )
UNION ALL
( SELECT 'name' AS some_string )
ORDER BY some_string
In this particular case, we can get the ordering we need by a simple reference to the column in the ORDER BY clause.
In the more general case, when there isn't a convenient expression for the ORDER BY clause, I would add an additional column, and perform a SELECT on the resultset from the UNION ALL operation. In this example, that "extra" column is named seq:
SELECT t.some_string
FROM ( SELECT 'assword' AS some_string, 1 AS seq
UNION ALL SELECT 'name', 2
)
ORDER BY t.seq
As another example:
( SELECT 'do' AS tone, 1 AS seq )
UNION ALL ( SELECT 're', 2 )
UNION ALL ( SELECT 'mi', 3 )
UNION ALL ( SELECT 'fa', 4 )
ORDER BY seq
I'd only need to add an outer SELECT if I needed a projection operation (for example, to remove the seq column from the returned resultset.
SELECT t.tone
FROM ( SELECT 'do' AS tone, 1 AS seq
UNION ALL SELECT 're', 2
UNION ALL SELECT 'mi', 3
UNION ALL SELECT 'fa', 4
)
ORDER BY t.seq