Mysql optimization help needed - mysql

I have a table TABLE_A with 4397898 records
+-------------------+---------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------------+---------------+------+-----+---------+----------------+
| id | bigint(11) | NO | PRI | NULL | auto_increment |
| usrid | int(11) | YES | | NULL | |
| grpid | int(11) | YES | | NULL | |
| catid | int(11) | YES | MUL | NULL | |
| folderid | int(11) | NO | MUL | 5 | |
| popid | int(11) | YES | MUL | NULL | |
| accid | int(11) | YES | MUL | NULL | |
| contentid | bigint(11) | YES | MUL | NULL | |
| priority | smallint(6) | YES | | NULL | |
| rating | smallint(6) | NO | | 3 | |
| fromid | int(11) | YES | | NULL | |
| ctxid | varchar(255) | YES | | NULL | |
| ctxmsgid | varchar(255) | YES | | NULL | |
| starred | enum('Y','N') | YES | | N | |
| links | enum('y','n') | YES | | n | |
+-------------------+---------------+------+-----+---------+----------------+
and it is indexed as below
+---------+----+--------------+-----+-------------+-----+-------------+----------+--------+------+------------+
| Table | Nu | Key_name | Seq | Column_name | Col | Cardinality | Sub_part | Packed | Null | Index_type |
+---------+----+--------------+-----+-------------+-----+-------------+----------+--------+------+------------+
| TABLE_A | 0 | PRIMARY | 1 | id | A | 4617132 | NULL | NULL | | BTREE |
| TABLE_A | 1 | catIndx | 1 | catid | A | 256507 | NULL | NULL | YES | BTREE |
| TABLE_A | 1 | contentIndx | 1 | contentid | A | 4617132 | NULL | NULL | YES | BTREE |
| TABLE_A | 1 | catIndx_2 | 1 | catid | A | 18 | NULL | NULL | YES | BTREE |
| TABLE_A | 1 | catIndx_2 | 2 | popid | A | 2013 | NULL | NULL | YES | BTREE |
| TABLE_A | 1 | folderidIndx | 1 | folderid | A | 13619 | NULL | NULL | | BTREE |
| TABLE_A | 1 | accIndex | 1 | accid | A | 1532 | NULL | NULL | YES | BTREE |
| TABLE_A | 1 | popindx | 1 | popid | A | 1532 | NULL | NULL | YES | BTREE |
+---------+----+--------------+-----+-------------+-----+-------------+----------+--------+------+------------+
The following query
explain SELECT
intCommIndx
FROM TABLE_A
WHERE (
(popid IN('-1',2407 ,22 ,1203 ,1342 ,1207 ,3 ,1254 ,2663 ,1250 ,3461 ,1251 ,14 ,1174 ,120 ,2406 ,2402 ,325 ,925 ,1210 ,2280 ,1 ,1202 ,1560 ,775 ,776 ,789 ,777 ,778 ,12 ,779 ,780 ,781 ,782 ,783 ,784 ,785 ,786 ,787 ,788 ,1209 ,19 ,26 ,9 ,24 ,4 ,25 ,21 ,18 ,1309 ,967 ,1212 ,6 ,9633 ,5 ,2671 ,17 ,13 ,1211 ,749 ,752 ,747 ,750 ,748 ,9302 ,1470 ,190 ,188 ,9711 ,9710 ,9512 ,11512 ,9514 ,9515 ,9516 ,11511 ,9513 ,9316 ,9453 ,1641 ,4986 ,1639 ,1640 ,7814 ,10042 ,9452 ,11236 ,11241 ,11238 ,11239 ,11237 ,11242 ,11240 ,1711 ) OR intpop3indx = -1)
AND catid = 5 )
explain SELECT
id
FROM TABLE_A
WHERE (
(popid IN('-1',2407 ,22 ,1203 ,1342 ,1207 ,3 ,1254 ,2663 ,1250 ,3461 ,1251 ,14 ,1174 ,120 ,2406 ,2402 ,325 ,925 ,1210 ,2280 ,1 ,1202 ,1560 ,775 ,776 ,789 ,777 ,778 ,12 ,779 ,780 ,781 ,782 ,783 ,784 ,785 ,786 ,787 ,788 ,1209 ,19 ,26 ,9 ,24 ,4 ,25 ,21 ,18 ,1309 ,967 ,1212 ,6 ,9633 ,5 ,2671 ,17 ,13 ,1211 ,749 ,752 ,747 ,750 ,748 ,9302 ,1470 ,190 ,188 ,9711 ,9710 ,9512 ,11512 ,9514 ,9515 ,9516 ,11511 ,9513 ,9316 ,9453 ,1641 ,4986 ,1639 ,1640 ,7814 ,10042 ,9452 ,11236 ,11241 ,11238 ,11239 ,11237 ,11242 ,11240 ,1711 ) OR popid = -1)
AND catid = 5 )
gives
+----+-------------+---------+------+---------------------------+---------+---------+-------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------+------+---------------------------+---------+---------+-------+--------+-------------+
| 1 | SIMPLE | TABLE_A | ref | catIndx,catIndx_2,popindx | catIndx | 5 | const | 649800 | Using where |
+----+-------------+---------+------+---------------------------+---------+---------+-------+--------+-------------+
How to improve the speed of the query?
There are only 850 rows in the result.
mysql> SELECT
-> count(id)
-> FROM TABLE_A
-> WHERE (
-> (popid IN('-1',2407,22,1203,1342,1207,3,1254,2663,1250,3461,1251,14,1174,120,2406,2402,325,925,1210,2280,1,1202,1560,775,776,789,777,778,12,779,780,781,782,783,784,785,786,787,788,1209,19,26,9,24,4,25,21,18,1309,967,1212,6,9633,5,2671,17,13,1211,749,752,747,750,748,9302,1470,190,188,9711,9710,9512,11512,9514,9515,9516,11511,9513,9316,9453,1641,4986,1639,1640,7814,10042,9452,11236,11241,11238,11239,11237,11242,11240,1711) OR intpop3indx = -1)
-> AND catid = 5 );
+--------------------+
| count(id) |
+--------------------+
| 850 |
+--------------------+
1 row in set (11.22 sec)
What changes can I make to get these 850 records within milliseconds?

This is the query:
SELECT intCommIndx
FROM TABLE_A
WHERE ( (popid IN('-1',2407 ,22 ,1203 ,1342 ,1207 ,3 ,1254 ,2663 ,1250 ,3461 ,1251 ,14 ,1174 ,120 ,2406 ,2402 ,325 ,925 ,1210 ,2280 ,1 ,1202 ,1560 ,775 ,776 ,789 ,777 ,778 ,12 ,779 ,780 ,781 ,782 ,783 ,784 ,785 ,786 ,787 ,788 ,1209 ,19 ,26 ,9 ,24 ,4 ,25 ,21 ,18 ,1309 ,967 ,1212 ,6 ,9633 ,5 ,2671 ,17 ,13 ,1211 ,749 ,752 ,747 ,750 ,748 ,9302 ,1470 ,190 ,188 ,9711 ,9710 ,9512 ,11512 ,9514 ,9515 ,9516 ,11511 ,9513 ,9316 ,9453 ,1641 ,4986 ,1639 ,1640 ,7814 ,10042 ,9452 ,11236 ,11241 ,11238 ,11239 ,11237 ,11242 ,11240 ,1711 ) OR intpop3indx = -1
) AND
catid = 5
)
Queries with or can be quite hard to optimize. I would recommend creating two indexes on the table and then rewriting the query. The two indexes are intCommIndx(catid, popid, intCommIndx) and intCommIndx(catid, intpop3indx, intCommIndx). Then the new query is:
SELECT intCommIndx
FROM TABLE_A
WHERE catid = 5 and
popid IN ('-1',2407 ,22 ,1203 ,1342 ,1207 ,3 ,1254 ,2663 ,1250 ,3461 ,1251 ,14 ,1174 ,120 ,2406 ,2402 ,325 ,925 ,1210 ,2280 ,1 ,1202 ,1560 ,775 ,776 ,789 ,777 ,778 ,12 ,779 ,780 ,781 ,782 ,783 ,784 ,785 ,786 ,787 ,788 ,1209 ,19 ,26 ,9 ,24 ,4 ,25 ,21 ,18 ,1309 ,967 ,1212 ,6 ,9633 ,5 ,2671 ,17 ,13 ,1211 ,749 ,752 ,747 ,750 ,748 ,9302 ,1470 ,190 ,188 ,9711 ,9710 ,9512 ,11512 ,9514 ,9515 ,9516 ,11511 ,9513 ,9316 ,9453 ,1641 ,4986 ,1639 ,1640 ,7814 ,10042 ,9452 ,11236 ,11241 ,11238 ,11239 ,11237 ,11242 ,11240 ,1711 )
UNION
SELECT intCommIndx
FROM TABLE_A
WHERE catid = 5 and intpop3indx = -1;
This will allow each subquery to be satisfied only using the indexes.

I would try to put the last conditions in first position. So when one of them isn't verified, we pass directly to the other row :
catid = 5 AND (intpop3indx = -1 OR popid IN (...))
So when catid != 5, the query passes directly to the other row. (Even if catid = 5 AND intpop3indx = -1)

Your query is selecting column intCommIndx from the table, but that column does not appear as one of the table columns.
The quick answer is to create a "covering index" e.g.
... ON TABLE_A (catid, intpop3indx, popid, intCommIndx)
EXPLAIN output should show "Using index" in the Extra column, which means the query is satisfied entirely from the index without a need to look up pages from the table.

Related

How to create an index on a CONCAT("string" ,column) in mysql?

I have a table where id is primary key.
CREATE TABLE t1 (
id INT NOT NULL AUTO_INCREMENT,
col1 VARCHAR(45) NULL,
PRIMARY KEY (id));
I have another table t2 which is joining table t1 as
t2 LEFT JOIN t1 ON CONCAT("USER_", t1.id) = t2.user_id
I want to create an index which has CONCAT("USER_", t1.id) values indexed in any order.
I tried
ALTER TABLE t1 ADD INDEX ((CONCAT('user_',id) DESC);
but it is giving error.
I have followed official documentation of mysql.
Note : I do not want to create a new CONCAT("user_", id) column.
https://dev.mysql.com/doc/refman/8.0/en/create-index.html#create-index-column-prefixes
InnoDB supports secondary indexes on virtual generated columns.
https://dev.mysql.com/doc/refman/5.7/en/create-table-secondary-indexes.html
In 5.7(onward) you can use a generated column, then index that column. e.g.
Here is an example of taking the integer out of the string to create an efficient join:
CREATE TABLE myusers (
id mediumint(8) unsigned NOT NULL auto_increment
, name varchar(255) default NULL,
PRIMARY KEY (`id`)
) AUTO_INCREMENT=1
;
INSERT INTO myusers (`name`) VALUES ('Imelda'),('Hamish'),('Brandon'),('Amity'),('Jillian'),('Lionel'),('Faith'),('Dai'),('Reed'),('Molly');
CREATE TABLE mytable (
id mediumint(8) unsigned NOT NULL auto_increment
, user_id VARCHAR(20)
, ex_user_id integer GENERATED ALWAYS AS (0+substring(user_id,6,20))
, password varchar(255)
, PRIMARY KEY (`id`)
, INDEX idx_ex_user_id (ex_user_id)
) AUTO_INCREMENT=1
;
INSERT INTO mytable (`user_id`,`password`) VALUES
('user_1','PYX68BIC9RD')
,('user_2','LPY07EIN0UA')
,('user_3','UGC24TKI3JL')
,('user_4','YQU18ALB8YA')
,('user_5','DEL56AGR6AD')
,('user_6','YQN87UOB0PO')
,('user_7','CPC15JFU6MC')
,('user_8','MWC40ZWD2EE')
,('user_9','HEB34QQH0UM')
,('user_10','GVP36PLP5PW')
;
select
*
from myusers
inner join mytable on myusers.id = mytable.ex_user_id
;
id | name | id | user_id | ex_user_id | password
-: | :------ | -: | :------ | ---------: | :----------
1 | Imelda | 1 | user_1 | 1 | PYX68BIC9RD
2 | Hamish | 2 | user_2 | 2 | LPY07EIN0UA
3 | Brandon | 3 | user_3 | 3 | UGC24TKI3JL
4 | Amity | 4 | user_4 | 4 | YQU18ALB8YA
5 | Jillian | 5 | user_5 | 5 | DEL56AGR6AD
6 | Lionel | 6 | user_6 | 6 | YQN87UOB0PO
7 | Faith | 7 | user_7 | 7 | CPC15JFU6MC
8 | Dai | 8 | user_8 | 8 | MWC40ZWD2EE
9 | Reed | 9 | user_9 | 9 | HEB34QQH0UM
10 | Molly | 10 | user_10 | 10 | GVP36PLP5PW
explain select
*
from myusers
inner join mytable on myusers.id = mytable.ex_user_id
;
id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra
-: | :---------- | :------ | :--------- | :--- | :------------- | :------------- | :------ | :------------------------------------- | ---: | -------: | :----------
1 | SIMPLE | myusers | null | ALL | PRIMARY | null | null | null | 10 | 100.00 | null
1 | SIMPLE | mytable | null | ref | idx_ex_user_id | idx_ex_user_id | 5 | fiddle_HNTHMETRTFAHHKBIGWZM.myusers.id | 1 | 100.00 | Using where
db<>fiddle here
note the conversion of user_id from string to integer is "implicit":
To cast a string to a number, you normally need do nothing other than use the string value in numeric context:
https://dev.mysql.com/doc/refman/5.7/en/create-table-secondary-indexes.html

postgresql returns null but mysql doesn't

I have an application for which I am migrating from Mysql to Psql.
I have three tables t1,t2,t3 described below . Table t3 will always have a entry as long as user is available , but both table t1 and t2 may or may not have entry if the user doesn't create DB in his account.
While executing q1 in mysql , I get result set containing values fetched from table t3, even if t1 and t2 doesn't have entry , but it returns null in psql . So I've written two queries pq1 and pq2 to be equivalent to q1 . What is the reason that mysql doesn't return null values but psql does? Is there any better solution to this than breaking down into two queries for psql ?
mysql query (q1)
select
COALESCE(sum(dr.NO_OF_QT),0),
ur.NO_OF_USERS, ur.NO_OF_DB, 0,
COALESCE(sum(dr.NO_OF_SM),0),
COALESCE(sum(dr.NO_OF_RPTS),0)
from DataBaseProps dr
left join DataBaseDetails db on dr.DB_ID=db.ID and db.STATUS=1
left join UserProps ur on db.OWNER_UID=ur.USER_UID
where ur.USER_UID='USER_UID'
Psql-query_1 (pq1)
select
COALESCE(sum(dr.NO_OF_QT),0),
0,0, 0,
COALESCE(sum(dr.NO_OF_SM),0),
COALESCE(sum(dr.NO_OF_RPTS),0)
from DataBaseProps dr
left join DataBaseDetails db on dr.DB_ID=db.ID and db.STATUS=1
left join UserProps ur on db.OWNER_UID=ur.USER_UID
where ur.USER_UID='USER_UID'
psql-query_2(pq2)
select NO_OF_USERS,NO_OF_DB from UserProps
where USER_UID='USER_UID'
Table 1 DataBaseProps (t1)
desc DataBaseProps >
+-----------------+------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------------+------------+------+-----+---------+-------+
| DB_ID | bigint(19) | NO | PRI | NULL | |
| NO_OF_RPTS | int(10) | YES | | 0 | |
| NO_OF_QT | int(10) | YES | | 0 | |
| NO_OF_SM | int(10) | YES | | 0 | |
+-----------------+------------+------+-----+---------+-------+
Table 2 - DataBaseDetails(t2)
desc DataBaseDetails>
+-------------------+--------------+------+-----+-----------------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------------+--------------+------+-----+-----------------+-------+
| ID | bigint(19) | NO | PRI | NULL | |
| NAME | varchar(50) | NO | | NULL | |
| STATUS | int(10) | NO | | 1 | |
| OWNER_UID | bigint(19) | NO | | NULL | |
+-------------------+--------------+------+-----+-----------------+-------+
Table 3 UserProps(t3)
desc UserProps>
+-----------------+------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------------+------------+------+-----+---------+-------+
| USER_UID | bigint(19) | NO | PRI | NULL | |
| NO_OF_DB | int(10) | YES | | 0 | |
| NO_OF_USERS | int(10) | YES | | 0 | |
+-----------------+------------+------+-----+---------+-------+

Calculations of different columns and recording the calculated output in one row below in Mysql Query

I have a Table:-
----------------+--------------+--------------+--------------------+
| IsFirstChunk | BufferedTime | ElapsedTime | TotalBufferTime|
+----+--------------+----------------+--------------+--------------+
| Yes | 9.056693603959156 | 13.434 | NULL |
| NULL | 8.397168452045355 | 13.915 | NULL |
| NULL | 9.480674058760885 | 14.576 | NULL |
| NULL | 8.25989921902355 | 15.816 | NULL |
| NULL | 9.029792805273495 | 18.573 | NULL |
| NULL | 9.55641146650022 | 26.385 | NULL |
| NULL | 7.567281197192748 | 37.274 | NULL |
| NULL | 9.046965152922192 | 46.142 | NULL |
| NULL | 8.135399698570493 | 56.825 | NULL |
i want to calculate the columns BufferTime and ElapsedTime and insert that output to TotalBufferTime column but i want to record the output in one row below of the TotalBufferTime column not in the adjacent row.
I want to do something like this :-
update RequestInfo SET `TotalBufferTime` = BufferedTime + ElapsedTime;
only thing is i want record the output one row below of the TotalBufferTime
+--------------+--------------+--------------+--------------------+
| IsFirstChunk | BufferedTime | ElapsedTime | TotalBufferTime|
+----+--------------+----------------+--------------+--------------+
| Yes | 9.056693603959156 | 13.434 | 0 |
| NULL | 8.397168452045355 | 13.915 | 22.4906936 |
| NULL | 9.480674058760885 | 14.576 | 22.31216845 |
Try this:
update RequestInfo join (
select curr.id, (
select (prior.BufferedTime + prior.ElapsedTime) AS value
from RequestInfo prior
where prior.id < curr.id
order by prior.id desc
limit 1) value
from RequestInfo curr
) g on g.id = RequestInfo.id
set RequestInfo.TotalBufferTime = g.value;

Join by part of string

I have following tables:
**visitors**
+---------------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------------+--------------+------+-----+---------+----------------+
| visitors_id | int(11) | NO | PRI | NULL | auto_increment |
| visitors_path | varchar(255) | NO | | | |
+---------------------+--------------+------+-----+---------+----------------+
**fedora_info**
+----------------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------------+--------------+------+-----+---------+-------+
| pid | varchar(255) | NO | PRI | | |
| owner_uid | int(11) | YES | | NULL | |
+----------------+--------------+------+-----+---------+-------+
First I looking for visitors_path that are related to specific pages by:
SELECT visitors_id, visitors_path
FROM visitors
WHERE visitors_path REGEXP '[[:<:]]fedora/repository/.*:[0-9]+$';
The above query return expected result.
now .*:[0-9]+ in above query referred to pid in second table. now I want know count of result in above query grouped by owner_uid in second table.
How can I JOIN this tables?
EDIT
sample data:
visitors
+-------------+---------------------------------+
| visitors_id | visitors_path |
+-------------+---------------------------------+
| 4574 | fedora/repository/islandora:123 |
| 4575 | fedora/repository/islandora:123 |
| 4580 | fedora/repository/islandora:321 |
| 4681 | fedora/repository/islandora:321 |
| 4682 | fedora/repository/islandora:321 |
| 4704 | fedora/repository/islandora:321 |
| 4706 | fedora/repository/islandora:456 |
| 4741 | fedora/repository/islandora:456 |
| 4743 | fedora/repository/islandora:789 |
| 4769 | fedora/repository/islandora:789 |
+-------------+---------------------------------+
fedora_info
+-----------------+-----------+
| pid | owner_uid |
+-----------------+-----------+
| islandora:123 | 1 |
| islandora:321 | 2 |
| islandora:456 | 3 |
| islandora:789 | 4 |
+-----------------+-----------+
Expected result:
+-----------------+-----------+
| count | owner_uid |
+-----------------+-----------+
| 2 | 1 |
| 4 | 2 |
| 3 | 3 |
| 2 | 4 |
| 0 | 5 |
+-----------------+-----------+
I suggest you to normalize your database. When inserting rows in visitors extract pid in the front end language and put it in a separate column (e.g. fi_pid). Then you can join it easily.
The following query might work for you. But it'll be little cpu intensive.
SELECT
COUNT(a.visitors_id) as `count`,
f.owner_uid
FROM (SELECT visitors_id,
visitors_path,
SUBSTRING(visitors_path, ( LENGTH(visitors_path) -
LOCATE('/', REVERSE(visitors_path)) )
+ 2) AS
pid
FROM visitors
WHERE visitors_path REGEXP '[[:<:]]fedora/repository/.*:[0-9]+$') AS `a`
JOIN fedora_info AS f
ON ( a.pid = f.pid )
GROUP BY f.owner_uid
Following query returns expected result, but its very slow Query took 9.6700 sec
SELECT COUNT(t2.pid), t1.owner_uid
FROM fedora_info t1
JOIN (SELECT TRIM(LEADING 'fedora/repository/' FROM visitors_path) as pid
FROM visitors
WHERE visitors_path REGEXP '[[:<:]]fedora/repository/.*:[0-9]+$') t2 ON t1.pid = t2.pid
GROUP BY t1.owner_uid

query to return a single row with the multiple items in separate columns within the row

I have a situation where I return results with multiple rows. I'm looking for a way to return a single row, with the multiple items in separate columns within the row. My initial query:
SELECT a.name, a.city, a.address, a.abbrv, b.urltype, b.url
FROM jos__universityTBL as a
LEFT JOIN jos__university_urlTBL as b on b.universityID = a.ID
WHERE a.stateVAL = 'CA'
My output:
| University Of Southern Califor | Los Angeles | | usc | 2 | http://web-app.usc.edu/ws/soc/api/ |
| University Of Southern Califor | Los Angeles | | usc | 4 | http://web-app.usc.edu/ws/soc/api/ |
| University Of Southern Califor | Los Angeles | | usc | 1 | www.usc.edu |
| San Jose State University | San Jose | | sjsu | 2 | http://info.sjsu.edu/home/schedules.html |
| San Jose State University | San Jose | | sjsu | 4 | https://cmshr.sjsu.edu/psp/HSJPRDF/EMPLOYEE/HSJPRD/c/COMMUNITY_ACCESS.CLASS_SEARCH.GBL?FolderPath=PORTAL_ROOT_OBJECT.PA_HC_CLASS_SEARCH |
| San Jose State University | San Jose | | sjsu | 1 | www.sjsu.edu
My table schema...
mysql> describe jos_universityTBL;
+----------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------------+--------------+------+-----+---------+----------------+
| name | varchar(50) | NO | UNI | | |
| repos_dir_name | varchar(50) | NO | | | |
| city | varchar(20) | YES | | | |
| stateVAL | varchar(5) | NO | | | |
| address | varchar(50) | NO | | | |
| abbrv | varchar(20) | NO | | | |
| childtbl | varchar(200) | NO | | | |
| userID | int(10) | NO | | 0 | |
| ID | int(10) | NO | PRI | NULL | auto_increment |
+----------------+--------------+------+-----+---------+----------------+
9 rows in set (0.00 sec)
mysql> describe jos_university_urlTBL;
+--------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+--------------+------+-----+---------+----------------+
| universityID | int(10) | NO | | 0 | |
| urltype | int(5) | NO | | 0 | |
| url | varchar(200) | NO | MUL | | |
| actionID | int(5) | YES | | 0 | |
| status | int(5) | YES | | 0 | |
| ID | int(10) | NO | PRI | NULL | auto_increment |
+--------------+--------------+------+-----+---------+----------------+
6 rows in set (0.00 sec)
I'm really trying to get something like:
|<<the concated urltype-url >>|
ucs | losangeles | usc.edu | 1-u1 | 2-u2 | 3-u2 |
You could use group_concat:
SELECT a.name, a.city, a.address, a.abbrv, b.urltype,
group_concat(b.url SEPARATOR ' ')
FROM jos__universityTBL as a
LEFT JOIN jos__university_urlTBL as b on b.universityID = a.ID
WHERE a.stateVAL = 'CA'
GROUP BY a.name, a.city, a.address, a.abbrv, b.urltype
Generating dynamic columns is hard in SQL; if at all possible, see if it can be moved to the client side. If not, you can add a row number in a subquery, and give each row number its own colum. Here's an example with slightly different tables:
drop table if exists Universities;
drop table if exists Urls;
create table Universities (
id int auto_increment primary key
, Name varchar(50)
);
create table Urls (
id int auto_increment primary key
, UniversityId int
, Url varchar(50)
);
insert into Universities (name) values ('USC'), ('SJSU');
insert into Urls (UniversityId, Url) values
(1,'http://a/'), (1,'http://b/'),
(2,'http://c/'), (2,'http://d/'), (2,'http://e/');
SELECT
Name
, group_concat(case RowNr when 1 then Url end) as FirstCol
, group_concat(case RowNr when 2 then Url end) as SecondCol
, group_concat(case RowNr when 3 then Url end) as ThirdCol
FROM (
SELECT
u.Name
, l.Url
, (#i := case when #LastUni = u.Name then #i + 1 else 1 end) as RowNr
, #LastUni := u.name
FROM Universities u
JOIN Urls l ON u.id = l.UniversityId
JOIN (SELECT #i := 0, #LastUni := '') init
) subquery
GROUP BY Name;
This prints:
SJSU http://c/ http://d/ http://e/
USC http://a/ http://b/ NULL