Mysql. Select where field=1 or field=2 with IF - mysql

i need some query.
CREATE TABLE `location_areas_localized` (
`id` int(11) DEFAULT NULL,
`lang_index` varchar(5) DEFAULT NULL,
`name` varchar(255) DEFAULT NULL,
KEY `id` (`id`),
KEY `lang_index` (`lang_index`),
KEY `name` (`name`),
FULLTEXT KEY `name_2` (`name`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
INSERT INTO `location_areas_localized` (`id`, `lang_index`,`name`)
VALUES
(1,'ru','Нью Йорк'),
(1,'en','New York'),
(2,'en','Boston'),
(2,'ch','波士顿')
;
Logic of search.
If row with lang_index='ru' AND id IN(1,2) found. it must return all with lang_index='ru'
If one or more rows with lang_index='ru' not exists But exists with lang_index='en' and with some id.
Then it must return all exists with land_index='ru' AND id IN(1,2) and all that not found with lang_index='ru' but found with lang_index='en' (in table - all rows with lang_index='en' always exists)
See on sqlfiddle
I need only one result per id. I tried GROUP BY id but its not works correctly.
Output must be
1,'ru','Нью Йорк'
2,'en','Boston' (because lang_index='ru' with id 2 not found)

SELECT
coalesce(max(CASE WHEN lang_index='ru' THEN name ELSE null END), name) as name
FROM
location_areas_localized
WHERE
id IN (1,2)
AND (lang_index='en' OR lang_index='ru')
group by
id
ORDER BY
FIELD(lang_index,'ru','en');

Without using aggregation functions, it only takes the first matching row. The subquery with ORDER BY enforce the fact that for the same id either the "ru" (or "en", if "ru" is not present) row is the first one.
SELECT *
FROM(
SELECT *
FROM location_areas_localized
ORDER BY FIELD(lang_index,'ru','en','ch')
) as inv
WHERE id IN (1,2)
GROUP BY id
See SQLFiddle example

Related

how to count items inside group_concat method with mysql query

I have one to many table relationship :
one user for multiple event
one event for multiple event_attribute
Now, I group by userId and want to know how many for each event attribute ?
I am using group_concat like this:
group_concat(
concat(event_event_attribute.event_attr_id,
count( distinct event_event_attribute.value)
) group by event_attr_id)
)
group by userId
So here, I first group by userId, then group concat event-attribute, at least I hope to have :
(attr1, 10),(attr2, 30)....
all in one row.
But this does not work at all
Any suggestions?
To be more specific, this is the DB schema I am using:
CREATE TABLE `user` (
`id` int(11) NOT NULL,
`name` varchar(45) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `id_UNIQUE` (`id`)
);
CREATE TABLE `event` (
`id` int(11) NOT NULL,
`name` varchar(45) DEFAULT NULL,
`user_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
);
CREATE TABLE `event_attr` (
`id` int(11) NOT NULL,
`att_name` varchar(45) DEFAULT NULL,
`event_id` varchar(45) DEFAULT NULL,
PRIMARY KEY (`id`)
);
INSERT INTO `user` VALUES (1,'user1'),(2,'user2'),(3,'user3');
INSERT INTO `event` VALUES (1,'event1',1),(2,'event2',1),(3,'event3',1),(4,'event4',2),(5,'event5',2),(6,'event6',3);
INSERT INTO `event_attr` VALUES (1,'att1','1'),(2,'att2','1'),(3,'att3','1'),(4,'att1','2'),(5,'att2',NULL);
Now if I am running:
select u.id, group_concat(e.name)
from user u
join event e on u.id=e.user_id
group by u.id
I will get:
1 event1,event2,event3
2 event4,event6
3 event 6
That is fine. But one step forward, I need to know count for each event_attt for each user, such as:
1 evet_att1:3;event_att2:2
2 event_att3:1
Then it is not possible. Can I use just one query to get above expected response?
should be the inverse alias concat the aggreagted values and not aggregated the concat
select concat (group_concat(event_event_attribute.event_attr_id )
,' - ',
count( distinct event_event_attribute.value) )
from event_event_attribute
group by userid
Otherwise could be you need an subquery for obtain the count group by event_attr_id
select group_concat(
concat(event_attr_id), ',', count_value)
)
from t (
select user_id, event_event_attribute.event_attr_id, count( distinct event_event_attribute.value) count_value
from event_event_attribute
group by event_attr_id
) t
group by user_id

Sort the order of "ORDER BY" query

I need to somehow order the ORDER BY column by using another table's order.
Table that contains sort:
CREATE TABLE IF NOT EXISTS `menu_category` (
`CATEGORY_ID` int(11) NOT NULL AUTO_INCREMENT,
`CATEGORY_NAME` varchar(20) NOT NULL,
`BUTTON_SORT` int(11) DEFAULT NULL,
PRIMARY KEY (`CATEGORY_ID`),
UNIQUE KEY `CATEGORY_NAME` (`CATEGORY_NAME`),
);
Keep in mind that BUTTON_SORT can be null.
Table that needs grouping:
CREATE TABLE IF NOT EXISTS `ticket_item` (
`TICKET_ITEM_ID` int(11) NOT NULL AUTO_INCREMENT,
`TICKET_ITEM_DESC` varchar(30) NOT NULL,
`TICKET_PRINT_CAT` varchar(40) NOT NULL,
PRIMARY KEY (`TICKET_ITEM_ID`),
);
I currently use this query:
SELECT
TICKET_ITEM_ID,
TICKET_ITEM_DESC
FROM ticket_item
WHERE
ticket_item.TICKET_ID = 1
GROUP BY TICKET_PRINT_CAT
What this ends up doing is that it will group everything correctly, but the order of which it is printed is just alphabetical. I need to sort the groups by order of BUTTON_SORT instead. I have no idea where to start for this.
EDIT: I apologize, TICKET_PRINT_CAT and CATEGORY_NAME are relative.
SELECT
TICKET_ITEM_ID,
TICKET_ITEM_DESC
FROM ticket_item
INNER JOIN menu_category ON menu_category.CATEGORY_NAME=ticket_item.TICKET_PRINT_CAT
WHERE
ticket_item.TICKET_ID = 1
GROUP BY TICKET_PRINT_CAT
ORDER BY menu_category.BUTTON_SORT
You need to use joins here. This creates a result set that can have values from both tables, and also can be ordered or grouped by values from either table.
SELECT
ticket_item.TICKET_ITEM_ID, ticket_item.TICKET_ITEM_DESC
FROM ticket_item
LEFT JOIN table2 on ticket_item.someColumnOnTable1 = table2.someColumnOnTable2
ORDER BY table2.whateverColumnYouWantToOrderBy

How to use INSERT ... SELECT with a particular column auto-incrementing, starting at 1?

I am using INSERT ... SELECT to insert a data from specific columns from specific rows from a view into a table. Here's the target table:
CREATE TABLE IF NOT EXISTS `queue` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`customerId` int(11) NOT NULL,
`productId` int(11) NOT NULL,
`priority` int(11) NOT NULL,
PRIMARY KEY (`ID`),
KEY `customerId` (`customerId`),
KEY `productId` (`productId`),
KEY `priority` (`priority`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;
The INSERT ... SELECT SQL I have works, but I would like to improve it if possible, as follows: I would like the inserted rows to start with 1 in the priority column, and each subsequent row to increment the priority value by 1. So, if three rows were inserted, the first would be priority 1, the second 2, and the third 3.
A exception to the "start at 1" rule: if there are existing rows in the target table for the specified customer, I would like the inserted rows to start with MAX(priority)+1 for that customer.
I thought I could use a subquery, but here's the problem: sometimes the subquery returns NULL (when there are no records in the queue table for the specified customer), which breaks the insert, as the priority column does not allow nulls.
I tried to CAST the column to an integer, but that still gave me NULL back when there are no records with that customer ID in the table.
I've hardcoded the customer ID in this example, but naturally in my application that would be an input parameter.
INSERT INTO `queue`
(
`customerId`,
`productId`,
`priority`,
`status`,
`orderId`)
SELECT
123, -- This is the customer ID
`PRODUCT_NO`,
(SELECT (MAX(`priority`)+1) FROM `queue` WHERE `customerId` = 123),
'queued',
null
FROM
`queue_eligible_products_view`
Is there a way to do this in one SQL statement, or a small number of SQL statements, i.e., less than SQL statement per row?
I do not think I can set the priority column to auto_increment, as this column is not necessarily unique, and the auto_increment attribute is used to generate a unique identity for new rows.
As Barmar mentions in the comments : use IFNULL to handle your sub query returning null. Hence:
INSERT INTO `queue`
(
`customerId`,
`productId`,
`priority`,
`status`,
`orderId`)
SELECT
123, -- This is the customer ID
`PRODUCT_NO`,
IFNULL((SELECT (MAX(`priority`)+1) FROM `queue` WHERE `customerId` = 123),1),
'queued',
null
FROM
`queue_eligible_products_view`
Here's how to do the incrementing:
INSERT INTO queue (customerId, productId, priority, status, orderId)
SELECT 123, product_no, #priority := #priority + 1, 'queued', null
FROM queue_eligible_products_view
JOIN (SELECT #priority := IFNULL(MAX(priority), 0)
FROM queue
WHERE customerId = 123) var

Query field has to match multiple values

I'm currently having an issue with my query and i can't figure out the final step in order to make it work.
The problem is that i have a filter option on my website which gives visitors the possibility to filter on specific settings.
My query so far is
SELECT DISTINCT `spt`.`title`
FROM `shop_product_specs` as `sps` JOIN
`shop_product_texts` as `spt`
ON `spt`.`product_id` = `sps`.`product_id`
WHERE `cat_spec_id` IN (2, 3) AND (`value` IN ("1200", "1400")) AND (`value` IN ("A", "A+"))
What i am trying to accomplish is that when i execute the query the value field matches multiple values.
So for example i want a product which has the cat_spec_id of 2 with the value of 1200 or 1400 BUT ALSO matches cat_spec_id of 3 with the value of "A" or "A+".
The main problem of the query is that it is the same field, so is this even possible?
This is my structure
CREATE TABLE IF NOT EXISTS `shop_product_specs` (
`product_spec_id` int(11) NOT NULL AUTO_INCREMENT,
`product_id` int(11) NOT NULL,
`cat_spec_id` int(11) NOT NULL,
`value` varchar(50) NOT NULL,
PRIMARY KEY (`product_spec_id`),
KEY `product_id` (`product_id`),
KEY `cat_spec_id` (`cat_spec_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=312 ;
I think this is an example of a set-within-sets subquery. Here is a method that solves this with aggregation and a having clause:
SELECT `spt`.`title`
FROM `shop_product_specs` as `sps` JOIN
`shop_product_texts` as `spt`
ON `spt`.`product_id` = `sps`.`product_id`
group by spt.title
having max(cat_spec_id = 2 and value in ('1200', '1400')) > 0 and
max(cat_spec_id = 3 and value in ('A', 'A+')) > 0
Each of the conditions in the having clause is verifying that a row exists with the corresponding conditions.

Find duplicates per parent id

I have two DB tabels which form a parent child relationship from Planung to Aufgabe:
Planung:
CREATE TABLE `planung` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`Bezeichnung` varchar(255) DEFAULT NULL,
-- lots of ohter columns
PRIMARY KEY (`id`),
) ENGINE=InnoDB
Aufgabe:
CREATE TABLE `aufgabe` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`planung_id` bigint(20) DEFAULT NULL, -- foreign key to Planung.id
`Nummer` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
-- lots of ohter columns
) ENGINE=InnoDB
I'm looking for a query which gives me all Planung.id and Aufgabe.ID for all duplicate Nummer per Planung. Or in other words: For every Planung Aufgabe.Nummer must be unique, I want to check whehter this is really the case in my DB (I know it isn't).
SELECT planung_id, GROUP_CONCAT(id) AS aufgabe_id, Nummer, COUNT(1) as num_duplicates
FROM aufgabe
GROUP BY planung_id, Nummer
HAVING COUNT(1) > 1
This query gives all planung_id which has duplicate Nummer and displays them like:
planung_id aufgabe_id Nummer num_duplicates
1 2,5,8 1 3
Which means, for Planung 1, there exists three Aufgabe with Nummer 1, and they are 2,5 and 8.
Edit: Shamelessly stolen from #dgw's comment:
Once you have run this query, and corrected all the duplicates. Add a unique index to aufgabe {planung_id, Nummer} to ensure that the database maintains this constraint:
ALTER TABLE aufgabe
ADD CONSTRAINT UNIQUE uq_planung_id_and_nummer (planung_id, Nummer)
select p.id, a.id, a.Nummer from planung p
inner join aufgabe a on a.planung_id = p.id
group by p.id, a.id, a.Nummer having count(*) > 1
This will give you all elements from planung being more than once a parent.
SELECT planung_id,nummer,COUNT(*)
FROM aufgabe
GROUP BY 1,2 HAVING COUNT(*)>1 ;
This will give you every planung_id that has multiple Nummer values:
SELECT planung_id
FROM aufgabe
GROUP BY planung_id
HAVING COUNT(DISTINCT Nummer) > 1
If you also need the aufgabe.id, you can do this:
SELECT *
FROM aufgabe
WHERE
planung_id IN (
<query above>
)
If you need to enforce that at all times, consider adding a key on {planung_id, Nummer} (as #dgw has already suggested).