Editing the Results of a MySQL View - mysql

I'm trying to create a view in my relational MySQL database that will allow the user to update football match results from one (virtual) table within phpMyAdmin.
I have the view all setup visually how I want, and I am able to edit most of the fields, except I am getting error messages. If, for instance, I update the number of goals scored for a team, I get the following error messages shown below. It will still update that record, however, because if I refresh the page, that particular entry will change to what I entered.
I am aware that you cannot have a primary key on a view, but in terms of indexing, shouldn't the existing relationships be sufficient for this to work?
Another issue is updating the referee field. As this is a concatenated field (first_name + last_name), I cannot attempt to update it from the view.
This is my database structure:
This is the code for my view:
CREATE VIEW `view1_match_main` AS
SELECT
`match_main`.`match_id` AS `Match ID`,
`season`.`season` AS `Season`,
`match_status`.`status_no` AS `Status`,
`match_main`.`date_time` AS `Date`,
`c1`.`club_name` AS `Home Club`,
`mr1`.`goal` AS `Home Goals`,
`mr2`.`goal` AS `Away Goals`,
`c2`.`club_name` AS `Away Club`,
CONCAT(`referee`.`referee_first_name`,
' ',
`referee`.`referee_last_name`) AS `Referee`,
`stadium`.`stadium_name` AS `Stadium`,
`match_main`.`attendance` AS `Attendance`,
`match_main`.`bbc_url` AS `BBC URL`,
`match_main`.`sky_url` AS `Sky URL`
FROM
((((((((`match_main`
LEFT JOIN `referee` ON ((`match_main`.`referee_id` = `referee`.`referee_id`)))
LEFT JOIN `season` ON ((`match_main`.`season_id` = `season`.`season_id`)))
LEFT JOIN `match_status` ON ((`match_main`.`status_id` = `match_status`.`status_id`)))
LEFT JOIN `match_result` `mr1` ON (((`mr1`.`match_id` = `match_main`.`match_id`)
AND (`mr1`.`home_team` = 1))))
LEFT JOIN `club` `c1` ON ((`c1`.`club_id` = `mr1`.`club_id`)))
LEFT JOIN `match_result` `mr2` ON (((`mr2`.`match_id` = `match_main`.`match_id`)
AND (`mr2`.`home_team` = 0))))
LEFT JOIN `club` `c2` ON ((`c2`.`club_id` = `mr2`.`club_id`)))
LEFT JOIN `stadium` ON ((`c1`.`stadium_id` = `stadium`.`stadium_id`)))
ORDER BY `season`.`season` DESC , `match_main`.`date_time` , `c1`.`club_name`

Related

MySQL UPDATE with JOINS using MAX

I'm no MySQL guru.
I'm trying to update a table clients.converted from projects.last_update column.
DATETIME: clients.converted (new column as of now).
DATETIME: projects.last_update.
BOOLEAN: projects.converted.
For each client's project, there is the possibility to end the project with a prospect-to-client conversion, if so, (boolean) projects.converted will me TRUE.
What I want is to do an UPDATE statement on clients to fill clients.converted from MAX(projects.last_update) WHERE project's projects.converted = true.
So far I have tried a couple of queries, but this one grasps the idea in a less-confusing way:
UPDATE clients AS `Client`
INNER JOIN projects AS `Project` ON Project.client_id = Client.id
SET Client.converted = MAX(Project.last_update)
WHERE Project.converted = TRUE;
But it's not working (because I can't use MAX function directly on assignment) and I've run out of ideas on how to do an UPDATE with JOINS using the MAX function applied to a DATETIME column.
I did a SELECT statement to gather the information I need first and
it works like a charm:
SELECT Client.id, count(*), MAX(Project.last_update) FROM projects AS `Project`
LEFT JOIN clients AS `Client` ON Client.id = Project.client_id
WHERE Project.converted = TRUE
GROUP BY Client.id;
Any help is very much appreciated!
Thanks in advance.
MAX is an aggregate function, which means it cannot (or rather, generally should not) be used without a GROUP BY; you'll need to use a subquery.
UPDATE clients AS `Client`
INNER JOIN (SELECT client_id, MAX(last_update) AS max_lu
FROM projects
WHERE converted = TRUE
GROUP BY client_id
) AS `Project` ON Project.client_id = Client.id
SET Client.converted = Project.max_lu
;

distinct in query repeating values

I wonder if anyone can spot the problem with this 'view' query to show only 'company' and 'materials'. The problem is that it shows each entry a separate time for each material and company. I'm using this view to populate a dropdown box in a form but I would only like it to show the distinct values for each column (company/materials) - as of now if, for example, end result is the company 'Anderson' twice but with different materials for each...it shows 'Anderson' twice. I've tried using DISTINCT after the select statement for each of the two, but I don't achieve what I want.
select `b`.`company` AS `company`, `bp`.`material` AS `material`
from (((`caseys_wrdp4`.`windows_brands_products` `bp`
left join `caseys_wrdp4`.`windows_brands` `b` on((`bp`.`brand_id` = `b`.`id`)))
join `caseys_wrdp4`.`Windows_last_submissions` `ls`)
join `caseys_wrdp4`.`windows_materials` `wm`)
where ((`bp`.`width` = round(`ls`.`width`,0))
and (`bp`.`height` = round(`ls`.`height`,0))
and (`bp`.`material` = `wm`.`name`)
and (`bp`.`type` = `ls`.`type`)
and if ((`ls`.`minimumbid` <> '0.00'),
(`bp`.`cost` between `ls`.`minimumbid` and `ls`.`maximumbid`),
(`bp`.`cost` <= `ls`.`maximumbid`)))
Possible answer:
Add GROUP_CONCAT and GROUP BY to your query:
select `b`.`company` AS `company`, GROUP_CONCAT(`bp`.`material`) AS `materials`
from (((`caseys_wrdp4`.`windows_brands_products` `bp`
left join `caseys_wrdp4`.`windows_brands` `b` on((`bp`.`brand_id` = `b`.`id`)))
join `caseys_wrdp4`.`Windows_last_submissions` `ls`)
join `caseys_wrdp4`.`windows_materials` `wm`)
where ((`bp`.`width` = round(`ls`.`width`,0))
and (`bp`.`height` = round(`ls`.`height`,0))
and (`bp`.`material` = `wm`.`name`)
and (`bp`.`type` = `ls`.`type`)
and if ((`ls`.`minimumbid` <> '0.00'),
(`bp`.`cost` between `ls`.`minimumbid` and `ls`.`maximumbid`),
(`bp`.`cost` <= `ls`.`maximumbid`)))
GROUP BY(`b`.`company`);
This will give you back a single row for each company w/ company and materials. materials will be a comma-separated list (#Barmar). You could then parse that field for the 2nd drop down.
Example Rows:
'Anderson' 'Wood,Vinyl'
'WM' 'Metal','Plastic'
Assuming you're building a webpage, depending on how you're building the DOM, you can either use javascript str.split(), https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/split, or on the server side, any language should work.

Taking one column from MySQL joined tables

I have a query in MySQL and I am making a crystal report by using this.
Now inside the query i have a column called scan_mode and it is coming from gfi_transaction table. This scan_mode I am using in report to suppress some sections. But some times this value is coming null for some transaction ids.
So now I want to take this scan_mode as separate query so that it will work.
Can any one please help how I can modify the below query to take only scan_mode column.
SELECT
cc.cost_center_code AS cccde,
cc.name AS ccnme,gf.scan_mode,
cc.cost_center_id AS ccid,
site.name AS siteme,
crncy.currency_locale AS currency_locale,
cntry.language AS LANGUAGE,
cntry.country_name AS cntrynm,
crncy.decimal_digits AS rnd,
gf.transaction_no AS Serial_No,
brnd.name AS brand_name,
rsn.description AS reason,
gf.comment AS COMMENT,
ts.status_description AS STATUS,
DATE_FORMAT(gf.created_date,'%d/%m/%Y') AS created_date,
gf.created_by AS created_by,
IFNULL(gf.approval_no,'Not authorized') AS Trans_no,
gf.approved_date AS approval_dt,
gf.approved_by AS approved_by,gf.status AS status1,
IFNULL(loc.cost_center_code,cc.cost_center_code) AS cur_location,
gf.document_ref_no,gf.document_ref_type,
,DATE_FORMAT(document_ref_date1,'%d/%m/%Y')) AS invoice_no
FROM
gfi_transaction gf
INNER JOIN gfi_instruction gfn ON (gf.transaction_id=gfn.transaction_id)
INNER JOIN gfi_document_instruction doc ON (gf.ref_transaction_no = doc.document_instruction_id)
INNER JOIN reason rsn ON (gf.reason_id = rsn.reason_id)
INNER JOIN gfi_status ts ON (gf.status = ts.gfi_status_id)
INNER JOIN transaction_type tt ON (gf.transaction_type_id = tt.transaction_type_id)
INNER JOIN brand brnd ON(gf.brand_id=brnd.brand_id)
-- cc details
INNER JOIN cost_center cc ON (brnd.parent_brand = cc.brand_id OR gf.brand_id = cc.brand_id)
INNER JOIN site site ON(cc.site_id = site.site_id)
INNER JOIN country cntry ON (site.country_id = cntry.country_id)
INNER JOIN currency crncy ON (cntry.currency_id=crncy.currency_id)
LEFT OUTER JOIN alshaya_location_details loc ON
(gf.brand_id = loc.brand_id AND loc.cost_center_id = gf.cost_centre_id)
LEFT OUTER JOIN alshaya_location_details locto ON
(locto.cost_center_id = gf.from_cost_center_id)
WHERE
gf.transaction_id='{?TransID}'
AND rsn.transaction_type_id IN (10,11,14)
wow, that's a big query. I ran across a similar problem in a query i was building and found the if syntax to be a solution to my problem. This was also answered in this question: MYSQL SELECT WITHIN IF Statement
$psdb->query = "SELECT count, s.classid,
if (k.sic != k.siccode, k.siccode, s.siccode) as siccode,
if (k.sic != k.siccode, k.sicdesc, s.sicdesc) as sicdesc,
if (k.sic != k.siccode, k.sicslug, s.sicslug) as sicslug
FROM ...
It looks like scan_mode column comes from "gfi_transaction" table which seems to be primary table in your query. If you get null for this column then it means your table itself have NULL value for this column. Taking that separately in a query wont solve your problem. Try replacing null with a default value and handle it in code. You can add default value instead of NULL by using ifnull(scan_mode, 'default')

Propel ORM - Joining a table to itself without a foreign key

I'm just getting started with Propel. I have a situation where I am left joining a table to itself to obtain a min value. I have the query written that works as I need it to, but I can't figure out how to do it using the Propel models.
This query gets the first successful payment made by each user that registered after a given date:
SELECT `p`.`id` AS `payment_id`,
`p`.`request_date`,
`u`.`id` AS `user_id`,
`u`.`registration_date`
FROM `payments` AS `p`
LEFT JOIN `payments` AS `filter`
ON `p`.`user_id` = `filter`.`user_id`
AND `p`.`id` > `filter`.`id`
INNER JOIN `users` AS `u`
ON `p`.`user_id` = `u`.`id`
AND `u`.`registration_date` >= '2013-07-28'
WHERE `p`.`completed` = 1
AND `filter`.`id` IS NULL
ORDER BY `u`.`registration_date` DESC
Please help me translate that to Propel code.
Try this:
<?php
$q = \PaymentsQuery::create();
$q->select(array('Payments.RequestDate', 'Users.RegistrationDate'));
$q->withColumn('Payments.Id', 'payment_id');
$q->withColumn('Users.Id', 'user_id');
$q->withAlias('Filter', \PaymentsPeer::TABLE_NAME);
// The object to join must ALWAYS be on the right side
$q->addJoin(\PaymentsPeer::USER_ID, \PaymentsPeer::alias('Filter', \PaymentsPeer::USER_ID), \ModelCriteria::LEFT_JOIN);
$q->addJoin(\PaymentsPeer::USER_ID, \UsersPeer::ID, \ModelCriteria::INNER_JOIN);
$q->where('Payments.Id > Filter.Id');
$q->where('User.RegistrationDate >= ?', '2013-07-28');
$q->where('Payments.Completed = ?', 1);
$q->where('Filter.Id IS NULL');
$q->orderBy(\UsersPeer::REGISTRATION_DATE, \ModelCriteria::DESC);
I want to use the add method for having columns equal each other, but this cannot be done because it will convert the second column into a string. I've asked this on the Propel Users Google Group with no response so far. Therefore, I'm not sure if the first and fourth where clauses will work.

Search with "MATCH AGAINST" causes CakePHP app to crash

I have two projects (A and B).
They're both built on CakePHP framework, and basically, they got the same structure, meaning that both their databases have the same structure. Let's say they are identical.
I have created a view, where I've put all the data needed to perform a search and I called it search_areas. Every column from the tables that are in the view are FULLTEXT indexes.
Now, when I perform a search on Project A, it works like a charm. But when I do it on project B, it takes forever. Actually, something jams, something in the code. The database works fine but the app is unusable for about 10 minutes. Has anybody encountered such a problem?
This is the sql that runs when a search is performed:
SELECT
Product.*,
MainImage.*,
Currency.rate,
Category.green_tax,
CategoriesCategory.full_alias,
(Product.price*Currency.rate + Category.green_tax)*1.24 as real_price,
MATCH (SearchArea.Cname,SearchArea.Mname,SearchArea.Pname,SearchArea.description,SearchArea.special_description,SearchArea.model,SearchArea.part_number,SearchArea.series,SearchArea.color,SearchArea.big_string) AGAINST ('+search term' IN BOOLEAN MODE) as score
FROM `products` AS `Product`
LEFT JOIN currencies AS `Currency` ON (`Product`.`currency` = `Currency`.`code`)
LEFT JOIN categories AS `Category` ON (`Product`.`category_id` = `Category`.`id`)
LEFT JOIN manufacturers AS `Manufacturer` ON (`Product`.`manufacturer_id` = `Manufacturer`.`id`)
LEFT JOIN categories_categories AS `CategoriesCategory` ON (`Product`.`category_id` = `CategoriesCategory`.`category_id`)
LEFT JOIN search_areas AS `SearchArea` ON (`SearchArea`.`id` = `Product`.`id`)
LEFT JOIN `product_images` AS `MainImage` ON (`MainImage`.`product_id` = `Product`.`id` AND `MainImage`.`main` = 1)
WHERE
MATCH (`SearchArea`.`Cname`,`SearchArea`.`Mname`,`SearchArea`.`Pname`,`SearchArea`.`description`,`SearchArea`.`special_description`,`SearchArea`.`model`,`SearchArea`.`part_number`,`SearchArea`.`series`,`SearchArea`.`color`,`SearchArea`.`big_string`) AGAINST ('+search term' IN BOOLEAN MODE)
AND `Product`.`active` = 1
LIMIT 15
Any ideas?
****** EDIT *****
I ran the query in mysql and it seems that there's the problem. It takes a very long time (2-5 minutes). Seems that I have to optimize my query, maybe find another solution. Thanks for helping. If anybody has an idea how to use the MATCH ... AGAINST ... syntax efficiently on a view or some concatenated element please post. I will probably abandon the above solution.
You are performing the filterings on a joined table 'SearchArea', no wonder it takes so long.
What your query does is, get all Products, join all the tables and then only keep what matches your filter. Your query should do the following, search SearchArea that have what your looking for and then only join the tables.
You should rewrite your query like so:
SELECT
Product.*,
MainImage.*,
Currency.rate,
Category.green_tax,
CategoriesCategory.full_alias,
(Product.price*Currency.rate + Category.green_tax)*1.24 as real_price,
MATCH (SearchArea.Cname,SearchArea.Mname,SearchArea.Pname,SearchArea.description,SearchArea.special_description,SearchArea.model,SearchArea.part_number,SearchArea.series,SearchArea.color,SearchArea.big_string) AGAINST ('+search term' IN BOOLEAN MODE) as score
FROM search_areas AS `SearchArea`
LEFT JOIN `products` AS `Product` ON (`SearchArea`.`id` = `Product`.`id`)
LEFT JOIN currencies AS `Currency` ON (`Product`.`currency` = `Currency`.`code`)
LEFT JOIN categories AS `Category` ON (`Product`.`category_id` = `Category`.`id`)
LEFT JOIN manufacturers AS `Manufacturer` ON (`Product`.`manufacturer_id` = `Manufacturer`.`id`)
LEFT JOIN categories_categories AS `CategoriesCategory` ON (`Product`.`category_id` = `CategoriesCategory`.`category_id`)
LEFT JOIN `product_images` AS `MainImage` ON (`MainImage`.`product_id` = `Product`.`id` AND `MainImage`.`main` = 1)
WHERE
MATCH (`SearchArea`.`Cname`,`SearchArea`.`Mname`,`SearchArea`.`Pname`,`SearchArea`.`description`,`SearchArea`.`special_description`,`SearchArea`.`model`,`SearchArea`.`part_number`,`SearchArea`.`series`,`SearchArea`.`color`,`SearchArea`.`big_string`) AGAINST ('+search term' IN BOOLEAN MODE)
AND `Product`.`active` = 1
LIMIT 15