distinct in query repeating values - mysql

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.

Related

filter table based on join but select all joins without taking filter into account

I have the following query generated with the Typeorm querybuilder
Current behavior:
Right now what is happening is that marines are correctly filtered but selected joins are also filtered by the given condition. returning only the dock that matches the condition instead of all the docks that belong to the marine.
Desired result:
I want to obtain all marines that have at least one dock whose name is 'dock 1'. And I want to include all docks belonging to that marine without taking their name into account.
How should i execute this query?
Any help would be much appreciated.
mariadb Ver 15.1
typeorm#0.2.37
SELECT `c`.`id` AS `c_id`,
`c`.`name` AS `c_name`,
`c`.`description` AS `c_description`,
`c`.`FkId` AS `c_FkId`,
`c`.`FkModel` AS `c_FkModel`,
`c`.`isActive` AS `c_isActive`,
`c`.`createdAt` AS `c_createdAt`,
`c`.`updatedAt` AS `c_updatedAt`,
`c`.`phones` AS `c_phones`,
`c`.`emails` AS `c_emails`,
`c`.`mainImage` AS `c_mainImage`,
`c`.`galleryImages` AS `c_galleryImages`,
`c`.`addressDetailsId` AS `c_addressDetailsId`,
`c_Docks`.`id` AS `c_Docks_id`,
`c_Docks`.`name` AS `c_Docks_name`,
`c_Docks`.`description` AS `c_Docks_description`,
`c_Docks`.`FkId` AS `c_Docks_FkId`,
`c_Docks`.`FkModel` AS `c_Docks_FkModel`,
`c_Docks`.`isActive` AS `c_Docks_isActive`,
`c_Docks`.`createdAt` AS `c_Docks_createdAt`,
`c_Docks`.`updatedAt` AS `c_Docks_updatedAt`,
`c_Docks`.`MarineId` AS `c_Docks_MarineId`
FROM `marine` `c`
LEFT JOIN `dock` `c_Docks` ON `c_Docks`.`MarineId` = `c`.`id`
WHERE `c`.`isActive` = true
AND (`c_Docks`.`name` = 'dock 1')
# ORDER BY c_id DESC
Step 1: Filter out all the rows relevant from table marine:
select from marine C where c.isActive = true
Step 2: Make the earlier SQL an inline view and left join it with table dock and apply the filter on dock table.
So, the SQL should look like this:
SELECT c.<column_names> ,
c_docks.<column_names>
FROM (
SELECT <column_names>
FROM marine
WHERE isActive = true) c
LEFT OUTER JOIN dock c_docks
ON c.id = c_docks.marine_id
AND c_docks.NAME = 'dock 1';
You can join with dock twice. Once to filter on the dock name, and another time to get all docks.
SELECT `c`.`id` AS `c_id`,
`c`.`name` AS `c_name`,
`c`.`description` AS `c_description`,
`c`.`FkId` AS `c_FkId`,
`c`.`FkModel` AS `c_FkModel`,
`c`.`isActive` AS `c_isActive`,
`c`.`createdAt` AS `c_createdAt`,
`c`.`updatedAt` AS `c_updatedAt`,
`c`.`phones` AS `c_phones`,
`c`.`emails` AS `c_emails`,
`c`.`mainImage` AS `c_mainImage`,
`c`.`galleryImages` AS `c_galleryImages`,
`c`.`addressDetailsId` AS `c_addressDetailsId`,
`c_Docks`.`id` AS `c_Docks_id`,
`c_Docks`.`name` AS `c_Docks_name`,
`c_Docks`.`description` AS `c_Docks_description`,
`c_Docks`.`FkId` AS `c_Docks_FkId`,
`c_Docks`.`FkModel` AS `c_Docks_FkModel`,
`c_Docks`.`isActive` AS `c_Docks_isActive`,
`c_Docks`.`createdAt` AS `c_Docks_createdAt`,
`c_Docks`.`updatedAt` AS `c_Docks_updatedAt`,
`c_Docks`.`MarineId` AS `c_Docks_MarineId`
FROM `marine` `c`
JOIN `dock` `c_Docks` ON `c_Docks`.`MarineId` = `c`.`id`
JOIN `dock` `dock_1` ON `dock_1`.`MarineId` = `c`.`id`
WHERE `c`.`isActive` = true
AND `dock_1`.`name` = 'dock 1'
There's no reason to use LEFT JOIN here, since you don't want to include marines with no matching dock.

Editing the Results of a MySQL View

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`

Select only distinct values for a particular column mysql

We have two tables in mysql database.Screenshots are attached below.
Given table ads_testTable
here is the screenshot of my dimesnionvalue_flattable
We have to run a query like the one below.
SELECT Quiz_Attempt.L1_Key dimID,
Quiz_Attempt.L1_Label CatVars,
COALESCE(**xyz**,0) AS series0
FROM DSQ_ADSSCHEMA.ADS_TestTable dataTable
RIGHT OUTER JOIN LS_CONFIG.DSQ_DIMENSIONVALUES_FLAT Quiz_Attempt on dataTable.Quiz_Attempt = Quiz_Attempt.L1_Key
WHERE Quiz_Attempt.L0_Key = 'All Levels' AND
Quiz_Attempt.DimensionID = 'Packet'
GROUP BY Quiz_Attempt.L1_Key, Quiz_Attempt.L1_Label;
My motive is to write a query in place of xyz so that I can get avg of obtainedMarks column in testtable according to the value of dimID I get.Each distinct Quiz_Attempt is a different test so If a Packet is repeating for a particular Quiz_Attempt in testTable, it should take only one value for that AttemptID.
I think you query could take the form of:
SELECT
L1_Key dimID,
L1_Label CatVars,
COALESCE('**xyz**',0) AS series0
FROM (
SELECT *
FROM (SELECT * FROM ADS_TestTable GROUP BY ADS_TestTable.Quiz_Attempt) dataTable
RIGHT OUTER JOIN DSQ_DIMENSIONVALUES_FLAT Quiz_Attempt on dataTable.Quiz_Attempt = Quiz_Attempt.L1_Key
WHERE Quiz_Attempt.L0_Key = 'All Levels' AND
Quiz_Attempt.DimensionID = 'Packet'
GROUP BY dataTable.Quiz_Attempt
) A GROUP BY dimID, CatVars;
The JOIN is done in an inner query, and grouped by Quiz_Attempt, so that you get a single row per attempt. This result is then used to compute what you need.

Multiple SQL count requests, one query

I'm brand new to SQL and I know this should be easy, but I can't seem to find any reference on how to do specifically what I'm looking for. I've check the archives and I can't find a basic example.
Anyway, all I want is -
SELECT
(COUNT (i.productNumber WHERE i.type = 'type1') AS 'Type 1'),
(COUNT (i.productNumber WHERE i.type = 'type2') AS 'Type 2'),
FROM items AS i
WHERE i.dateadded BETWEEN '2015-03-02' and '2015-03-04'
The two count conditions are different, but both of those queries share that date condition. I've done two distinct select statements and put a UNION between them. That works. The only issue is all of the data appears in one column under the first alias in the statement. I would need each alias to be a new column. I also have to write the date condition in twice.
You could group them by type so you would get a different row for each of them :
SELECT i.type, COUNT(i.productNumber)
FROM items i
WHERE i.dateadded BETWEEN '2015-03-02' AND '2015-03-04'
GROUP BY i.type;
If you really want to have one row, then you could do
SELECT COUNT(b.productNumber) AS 'type1', COUNT(c.productNumber) AS 'type2'
FROM items i
LEFT JOIN items b on b.productNumber = i.productNumber
LEFT JOIN items c on c.productNumber = i.productNumber
WHERE i.dateadded BETWEEN '2015-03-02' AND '2015-03-04'
AND b.type = 'type1'
AND c.type = 'type2';

MySQL Filtering Attributes

I am trying to create a better way of filtering items on a website. The actual filtering is working great but displaying the available options has stumped me.
I am using this sql query to get all the options for a specific category.
SELECT
atr1.`type` , atr1.`value`
FROM
`index-shop-filters` AS atr1
JOIN
`index-shop-filters` as atr2 ON atr1.`item` = atr2.`item`
WHERE
( atr2.`type` = 'sys-category' AND atr2.`value` = '1828' )
GROUP BY
atr1.`type`, atr1.`value`
But when I add a selected filter in the hope to get the remaining filters available. It doesn't give me the remaining filters. Instead it ignores the second OR statement.
SELECT
atr1.`type` , atr1.`value`
FROM
`index-shop-filters` AS atr1
JOIN
`index-shop-filters` as atr2 ON atr1.`item` = atr2.`item`
WHERE
( atr2.`type` = 'sys-category' AND atr2.`value` = '1828' )
OR ( atr2.`type` = 'Manufacturer' AND atr2.`value` = 'Sony' )
GROUP BY
atr1.`type`, atr1.`value`
I tried adding the HAVING COUNT(*) = 2 but that doesn't get the correct results.
The data in the index-shop-filters is like this.
item,type,value
the types are sys-category, manufacturer, size, color, etc.
When they select the first option (like sys-category) it will then display the available options. If they then select manufacturer (like sony) it will then display the available options that the items are sony, and in the category.
Ok, I think I finally understand what you're trying to do: you aren't trying to get a list of items, you're trying to get a list of item filters. Sorry, I should have picked up on that sooner.
Anyway, now I understand the problem, but I don't have a great answer. What you're trying to do is fairly complicated, and it can't be done with just one join (as far as I know). I can only think of two ways to do this: with multiple subqueries or with multiple joins. Both of these solutions are complicated and do not scale well, but it's all I can think of.
Here is one possible solution, using subqueries, that I do not recommend:
SELECT item, `type`, `value`
FROM `index-shop-filters` AS f
WHERE f.item IN (SELECT item FROM `index-shop-filters` WHERE `type` = 'sys-category' AND `value` = '1828')
AND f.item IN (SELECT item FROM `index-shop-filters` WHERE `type` = 'Manufacturer' AND `value` = 'Sony')
Here is a solution, using joins, that is better but still not great:
SELECT item, `type`, `value`
FROM `index-shop-filters` AS f
JOIN `index-shop-filters` AS f2 ON f.item = f2.item AND f2.`type` = 'sys-category' AND f2.`value` = '1828'
JOIN `index-shop-filters` AS f3 ON f.item = f3.item AND f3.`type` = 'Manufacturer' AND f3.`value` = 'Sony'
And that's all I've got. Both of those solutions should work, but they won't perform well. Hopefully someone else can come up with a clever, scalable answer.