How Can I Achieve This in Using MySQL? - mysql

I have a requirement that is
I have a table with partner and event details, each partner having number of events.Now i need to get the event details based on partnerid, means
partner1->event1
partner2->event1
.......
partnern->event1
Partner1->event2
partner2->event2
........
partnern->event2
...
.....
partner1->eventn
partner2->eventn
......
Here each partner having their own number of events.Please give me suggetions, I am using mysql
Here is my table sructure
CREATE TABLE `event` (
`eventid` varchar(30) NOT NULL DEFAULT '',
`partnerid` varchar(30) DEFAULT NULL,
PRIMARY KEY (`eventid`),
KEY `partnerid` (`partnerid`),
KEY `locationid` (`locationid`),
CONSTRAINT `event_ibfk_1` FOREIGN KEY (`partnerid`) REFERENCES `partnerprofile` (`userid`),
CONSTRAINT `event_ibfk_2` FOREIGN KEY (`locationid`) REFERENCES `location` (`locatinid`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

I am not that clear with your requirement. Anyway giving a try.
After you have mastered the basics of MySQL, take the next step and take on Aggregate Functions. Group BY is good for retrieving information about a group of data. If you only had one product of each type, then GROUP BY would not be all that useful.
GROUP BY only shines when you have many similar things. For example, if you have a number of partners of the same type, and you want to find out some statistical information like the minimum, maximum, or other top-level info, you would use GROUP BY.
Here is the updated solution:
SELECT A.`event_id` AS 'Event(ID)', B.`partner_names` AS 'Partners' FROM `event` A
JOIN
SELECT (SELECT GROUP_CONCAT( P.`partner_name`) AS 'partner_names'
FROM (SELECT `partner_name` FROM information_schema.columns
WHERE table_name='partnerprofile') as P) FROM `partnerprofile` B
GROUP BY A.`partnerid`
Here assume that partner_name is the name field in the partnerprofile table.
And the expected output is:
+---------------+--------------------------------------------+
| Event(ID) | Partners |
+---------------+--------------------------------------------+
| event_001 | Partener1, Partener2, Partener4 |
| event_002 | Partener2, Partener3, Partener9 |
| event_003 | Partener15 |
| event_004 | Partener5, Partener7, Partener9 |
| _________ | _________, _________ |
| _________ | _________ |
| _________ | _________, _________ _________, _________ |
| _________ | _________, _________, |
+---------------+--------------------------------------------+

I think an INNER JOIN should work. something like:
SELECT * FROM event INNER JOIN partner ON event.partnerID = partner.partnerID

Related

Add constraint so the column accepts only comma separated values from another column

I have these two tables:
CREATE TABLE `car_shop` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`selling_brands` varchar(25) DEFAULT NULL,
`some_col` varchar(25) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
CREATE TABLE `cars` (
`car_id` int(11) NOT NULL AUTO_INCREMENT,
`car_make` varchar(25) DEFAULT NULL,
PRIMARY KEY (`car_id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8
The second one is populated with following:
+--------+----------+
| car_id | car_make |
+--------+----------+
| 1 | BMW |
| 2 | Audi |
| 3 | Toyota |
+--------+----------+
I need to add such a constraint that column selling_brands would accept only values populated in car table (BMW, Audi, Toyota).
I imagine it that way:
+----+----------------+----------+
| id | selling_brands | some_col |
+----+----------------+----------+
| 1 | BMW, Audi | shop 1 |
| 2 | Toyota | shop 2 |
+----+----------------+----------+
I was trying to add constraint as follows, but it doesn't work:
ALTER TABLE car_shop
ADD FOREIGN KEY (selling_brands)
REFERENCES cars(car_make)
I'm getting: ERROR: (conn:24) Cannot add foreign key constraint
Error Code: 1215
Putting comma-separated values, or any sort of lists really, into a database is almost always a bad idea. Usually, when you think you need a "list", what you really need is another table; in your case:
cars
- car_id
- info about the car
shops
- shop_id
- info about the shop
car_shop
- car_id
- shop_id
If a shop "has" more than one car, more than one row in car_shop will reference its shop_id. If a car is in more than one shop, more than one row in car_shop will have its car_id. car_shop could also be used to contain information such as quantity, price, etc...

SQL Update table from another

I have table as following:
dev=> \d statemachine_history
Table "public.statemachine_history"
Column | Type | Modifiers
---------------+--------------------------+-------------------------------------------------------------------
id | bigint | not null default nextval('statemachine_history_id_seq'::regclass)
schema_name | character varying | not null
event | character varying | not null
identifier | integer | not null
initial_state | character varying | not null
final_state | character varying | not null
triggered_at | timestamp with time zone | not null default statement_timestamp()
triggered_by | text |
command | json |
flag | json |
created_at | timestamp with time zone |
created_by | json |
updated_at | timestamp with time zone |
updated_by | json |
Indexes:
"statemachine_log_pkey" PRIMARY KEY, btree (id)
"unique_statemachine_log_id" UNIQUE, btree (id)
"statemachine_history_identifier_idx" btree (identifier)
"statemachine_history_schema_name_idx" btree (schema_name)
AND
dev=> \d booking
Table "public.booking"
Column | Type | Modifiers
----------------+--------------------------+------------------------------------------------------
id | bigint | not null default nextval('booking_id_seq'::regclass)
pin | character varying |
occurred_at | timestamp with time zone |
membership_id | bigint |
appointment_id | bigint |
created_at | timestamp with time zone |
created_by | json |
updated_at | timestamp with time zone |
updated_by | json |
customer_id | bigint |
state | character varying | not null default 'booked'::character varying
Indexes:
"booking_pkey" PRIMARY KEY, btree (id)
Foreign-key constraints:
"booking_appointment_id_fkey" FOREIGN KEY (appointment_id) REFERENCES appointment(id)
"booking_customer_id_fkey" FOREIGN KEY (customer_id) REFERENCES customer(id)
"booking_membership_id_fkey" FOREIGN KEY (membership_id) REFERENCES membership(id)
Referenced by:
TABLE "booking_decline_reason" CONSTRAINT "booking_decline_reason_booking_id_fkey" FOREIGN KEY (booking_id) REFERENCES booking(id)
I am trying to update the booking.update_at from the statemachine_history.updated_at
Letting you know that there is a one to many relationship between the 2 tables so i want to MAX(statemachine_history.updated_at)
My try is:
UPDATE booking SET updated_at=
(
SELECT MAX(updated_at)
FROM statemachine_history
WHERE schema_name='Booking'
AND identifier=id
GROUP BY identifier
);
However the bookings.updated_at becomes null
All you really need to do is to make sure id reference booking.id by naming it explicitly;
UPDATE booking SET updated_at=
(
SELECT MAX(updated_at)
FROM statemachine_history
WHERE schema_name='Booking'
AND identifier = booking.id
GROUP BY identifier
);
A quick SQLfiddle to test with.
If there are real time requirements for the query, you'll want to look into TomH's join in another answer though.
This should do what you need:
UPDATE B
SET
updated_at = SQ.max_updated_at
FROM
Booking B
INNER JOIN
(
SELECT
identifier,
MAX(updated_at) AS max_updated_at
FROM
Statemachine_History SH
GROUP BY
identifier
) AS SQ ON SQ.identifier = B.id
[Solved] PSQL Query:
UPDATE booking SET updated_at=
(
SELECT MAX(updated_at)
FROM statemachine_history
WHERE schema_name='Booking'
AND identifier=booking.id
GROUP BY identifier
) WHERE exists(SELECT id FROM statemachine_history WHERE schema_name='Booking' AND identifier=booking.id);
This part:
WHERE exists(SELECT id FROM statemachine_history WHERE schema_name='Booking' AND identifier=booking.id);
is to avoid updating booking.updated_at, in case there is not such relation in statemachine_history table

MySQL range query is slow

I have read different links like http://goo.gl/1nr3s2, http://goo.gl/gv4Vlc and other stackoverflow questions, but none of them help me with this problem.
This problem interacts with multiple tables, but the EXPLAIN method help me identify range is the main problem with the query.
First I need to explain that I have this table with this sample data (I will not use ids in any table to simplify the process)
+-------+----------+----------------+--------------+---------------+----------------+
| marca | submarca | modelo_inicial | modelo_final | motor | texto_articulo |
+-------+----------+----------------+--------------+---------------+----------------+
| Buick | Century | 1993 | 1996 | 4 Cil 2.2 Lts | BE1254AG4 |
| Buick | Century | 1993 | 1996 | 4 Cil 2.2 Lts | 854G4 |
+-------+----------+----------------+--------------+---------------+----------------+
This table has more than 1.5 Million rows and I have created a index that integrates initial_year and end_year in one and also initial_year has an index and end_year has another index independently like this structure.
CREATE TABLE `general` (
`id_general` int(11) NOT NULL AUTO_INCREMENT,
`id_marca_submarca` int(11) NOT NULL,
`id_modelo_inicial` int(11) NOT NULL,
`id_modelo_final` int(11) NOT NULL,
`id_motor` int(11) NOT NULL,
`id_articulo` int(11) NOT NULL,
PRIMARY KEY (`id_general`),
KEY `fk_general_articulo` (`id_articulo`),
KEY `modelo_inicial_final` (`id_modelo_inicial`,`id_modelo_final`),
KEY `indice_motor` (`id_motor`),
KEY `indice_marca_submarca` (`id_marca_submarca`),
KEY `indice_modelo_inicial` (`id_modelo_inicial`),
KEY `indice_modelo_final` (`id_modelo_final`),
CONSTRAINT `fk_general_articulo` FOREIGN KEY (`id_articulo`) REFERENCES `articulo` (`id_articulo`) ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=1191853 DEFAULT CHARSET=utf8
I have another table that contains different years like this sample data:
+---------+----------------+
| id_modelo | texto_modelo |
+-----------+--------------+
| 76 | 2014 |
| 75 | 2013 |
............................
| 1 | 1939 |
+-----------+--------------+
I created a query that contains subquery to obtain specific data but took a lot of time. I will put some queries I have tried but none of them have worked properly for me
SELECT DISTINCT M.texto_modelo
FROM general G
INNER JOIN parque_vehicular.modelo M ON G.id_modelo_inicial <= M.id_modelo AND G.id_modelo_final >= M.id_modelo
WHERE EXISTS
(
SELECT DISTINCT A.id_articulo
...subquery...
WHERE A.id_articulo = G.id_articulo AND AD.id_distribuidor = 1
)
ORDER BY M.texto_modelo DESC;
And this query took a lot of seconds, so I use EXPLAIN and report is:
This is another query I tried.
SELECT DISTINCT M.texto_modelo
FROM general G
INNER JOIN parque_vehicular_rigs.modelo M ON M.id_modelo BETWEEN G.id_modelo_inicial AND G.id_modelo_final
WHERE EXISTS
(
SELECT DISTINCT A.id_articulo
...subquery WHERE A.id_articulo = G.id_articulo AND AD.id_distribuidor = 1
)
ORDER BY M.texto_modelo DESC;
Some operations you could do to change the query plan:
OP1: Get rid of all the keys or indexes in table general.
OP2: Use SELECT 1 instead of SELECT DISTINCT A.id_articulo in the sub query in EXISTS.
Do these operations separately, compare the differences.

Estimate/speedup huge table self-join on mysql

I have a huge table:
CREATE TABLE `messageline` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`hash` bigint(20) DEFAULT NULL,
`quoteLevel` int(11) DEFAULT NULL,
`messageDetails_id` bigint(20) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `FK2F5B707BF7C835B8` (`messageDetails_id`),
KEY `hash_idx` (`hash`),
KEY `quote_level_idx` (`quoteLevel`),
CONSTRAINT `FK2F5B707BF7C835B8` FOREIGN KEY (`messageDetails_id`) REFERENCES `messagedetails` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=401798068 DEFAULT CHARSET=utf8 COLLATE=utf8_bin
I need to find duplicate lines this way:
create table foundline AS
select ml.messagedetails_id, ml.hash, ml.quotelevel
from messageline ml,
messageline ml1
where ml1.hash = ml.hash
and ml1.messagedetails_id!=ml.messagedetails_id
But this request is working >1 day already. This is too long. Few hours would be ok. How can I speed this up? Thanx.
Explain:
+----+-------------+-------+------+---------------+----------+---------+---------------+-----------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+----------+---------+---------------+-----------+-------------+
| 1 | SIMPLE | ml | ALL | hash_idx | NULL | NULL | NULL | 401798409 | |
| 1 | SIMPLE | ml1 | ref | hash_idx | hash_idx | 9 | skryb.ml.hash | 1 | Using where |
+----+-------------+-------+------+---------------+----------+---------+---------------+-----------+-------------+
You can find your duplicates like this
SELECT messagedetails_id, COUNT(*) c
FROM messageline ml
GROUP BY messagedetails_id HAVING c > 1;
If it is still too long, add a condition to split the request on an indexed field :
WHERE messagedetails_id < 100000
Is it required to do this solely with SQL? Because for such a number of records you would be better off to break this down into 2 steps:
First run the following query
CREATE TABLE duplicate_hashes
SELECT * FROM (
SELECT hash, GROUP_CONCAT(id) AS ids, COUNT(*) AS cnt,
COUNT(DISTINCT messagedetails_id) AS cnt_message_details,
GROUP_CONCAT(DISTINCT messagedetails_id) as messagedetails_ids
FROM messageline GROUP BY hash ORDER BY NULL HAVING cnt > 1
) tmp
WHERE cnt > cnt_message_details
This will give you the duplicate IDs for each hash and since you have an index on the hash field grouping by will be relatively fast. Now, by counting distinct messagedetails_id values and comparing you implicitly fulfill the requirement for different messagedetails_id
where ml1.hash = ml.hash
and ml1.messagedetails_id!=ml.messagedetails_id
Use a script to check each record of the duplicate_hashes table

StringInString Query?

I have this database where I have stored some tags in it.
I stored the tags like this:
"humor,funny,animal"
Now I need a mysql query that selects this line when I search for "humor", "funny" or "animal". What I have until now:
SELECT id FROM database WHERE tags REGEXP 'humor' LIMIT 1
Unfortunately, it does not work. Could someone of you please help me out?
Edit: Thanks for all the responses! I will now need to study this first! But problem solved :)
Short Term
Because the tags are stored as denormalized data, use the FIND_IN_SET function:
SELECT t.id
FROM YOUR_TABLE t
WHERE FIND_IN_SET('humour', t.tags) > 0
Long Term Solution
Setup the tables to properly handle a many-to-many relationship:
TAGS
tag_id (primary key)
tag_description
ITEMS
item_id (primary key)
ITEM_TAGS
item_id (primary key, foreign key to ITEMS.item_id)
tag_id (primary key, foreign key to TAGS.tag_id)
Making the two columns in ITEM_TAGS the primary key means you don't have to worry about duplicates. And yes, this means using the InnoDB engine...
Then, you can use:
SELECT i.item_id
FROM ITEMS i
WHERE EXISTS (SELECT NULL
FROM ITEM_TAGS it
JOIN TAGS t ON t.tag_id = it.tag_id
WHERE t.tag_description = 'humour'
AND it.item_id = i.item_id)
You can use LIKE
SELECT id FROM database WHERE tags LIKE '%humor%' LIMIT 1
Which will search for any entry where 'humor' is a substring. Note this will also return items tagged 'humorous'.
But like others said, having a separate table for tags would be best. To do this you will also need a pivot table.
So for example
-------------- data -------------
| ID | NAME |
| 1 | example |
| 2 | example 2 |
-----------------------------------
-------------- tags -------------
| ID | NAME |
| 1 | humor |
| 2 | cats |
| 3 | wumpus |
-----------------------------------
------------ data_tags ----------
| DATA_ID | TAG_ID |
| 1 | 1 |
| 1 | 2 |
| 2 | 1 |
| 2 | 3 |
-----------------------------------
To expand on Tomalak's comment, this would be best solved using a many-to-many relationship for database to tag relationships. This involves adding two new tables. Something like this (forgive my rusty MySQL)
CREATE TABLE `Tag` (
id INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
tag VARCHAR(64) NOT NULL,
PRIMARY KEY (id),
UNIQUE (tag)
) ENGINE=InnoDB;
CREATE TABLE `DatabaseTag` (
database_id INT(11) UNSIGNED NOT NULL, -- just guessing your database.id type here
tag_id INT(11) UNSIGNED NOT NULL,
PRIMARY KEY (database_id, tag_id),
FOREIGN KEY (database_id) REFERENCES `database` (id)
ON DELETE CASCADE,
FOREIGN KEY (tag_id) REFERENCES `Tag` (id)
ON DELETE CASCADE
) ENGINE=InndoDB;
Then, to find all the database records matching tag "humour", your query would look like
SELECT id FROM `database` d
INNER JOIN `DatabaseTag` dt ON d.id = dt.database_id
INNER JOIN `Tag` t ON dt.tag_id = t.id
WHERE t.tag = 'humour'