id | category
001 | 1000
001 | 300
002 | 500
003 | 200;300;100
004 | 100;300
005 | 200;3000
The result should be
Category | Total
1000 | 1
300 | 3
500 | 1
200 | 2
100 | 2
How can I arrive on that result? I saw something that I need to use find_in_set but its kind of complicated for me.
Any help on this will be greatly appreciated!
PS: I know the solution for this is to normalize but I guess it's a big work and I don't have an access to change database structure. So I guess if there's a solution to make a query work that will be great! :)
Thanks you!
Ok. my folt on previous answer!
Below is a way to split a string by a delimiter in MySQL without using a stored procedure.
To use the method you will first need to have another table that has numbers from 1 up to however many choices each row can store. This table will be used in a join, so that the first choice will be joined to the row with number 1, the second choice to row 2, etc. So you would need a table like this:
id
1
2
3
4
5
...
Let's say your main table is called maintable with a category column, and your other table is called othertable with an id column (though you could use any table that had sequential numbers or id numbers).
this I used to create table for this exampe:
CREATE TABLE maintable (id INT, category VARCHAR(255));
INSERT INTO maintable VALUES (1, '1000'), (2, '300'), (3, '500'), 4, '200;300;100'), (4, '100;300'), (4, '200;3000');
CREATE TABLE othertable (id INT);
INSERT INTO othertable VALUES (1), (2), (3), (4), (5), (6), (7), (8);
this is mysql code:
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(maintable.category,';',othertable.id),';',-1) AS category,
COUNT(*) AS numtimes
FROM maintable INNER JOIN othertable ON
(LENGTH(category)>0 AND SUBSTRING_INDEX(SUBSTRING_INDEX(category,';',othertable.id),';',-1)
<> SUBSTRING_INDEX(SUBSTRING_INDEX(category,';',othertable.id-1),';', -1))
GROUP BY category ORDER BY category;
and i got this resoult:
category numtimes
100 2
1000 1
200 3
200 2
300 1
500 1
Related
I have some parent and daughter design-wise locations-id in the MySQL database.
Where the daughter linked to the parent. I will show the database design below -
I can able to fetch the data when I search it through daughter location id wise but I don't have any idea how I combined the daughter value when I click parent location.
For example -
MainLocation (123) //total stock 23+10+56= 89
|
|
|---- DaughterLoc1 (456) //suppose stock 23
|
|---- DaughterLoc2 (789) //suppose stock 10 and total stock 10+56 = 66
|
|
|---DaughterLocA (963) //suppose stock 56
SQL : SELECT stock FROM table WHERE location = '456'
OUTPUT = 23 (Corrent)
But I want when searching location 123 I want output 89
My table design is like this below -
table: LocParent
-------------------------
| ID | stock | loc_id |
-------------------------
| 1 | 10 | 789 |
-------------------------
`location`
--------------------------------------------------------------------------------
| ID | main_loc | main_loc_id | loc_under | loc_under_id | stock |
--------------------------------------------------------------------------------
| 1 | MainLocation | 123 | DaughterLoc1 | 456 | 23 |
--------------------------------------------------------------------------------
| 2 | MainLocation | 123 | DaughterLoc2 | 789 | 10 |
--------------------------------------------------------------------------------
It is hard to tell from your sample structure what things actually look like still, and it is further complicated by multiple things called an "id". But, generally speaking, if your depth is finite, you can make small sub-queries, and if your depth is infinite (or unbound) you can make a recursive query.
Here is a sample database. It doesn't match yours, but hopefully it make sense still. If it doesn't, it would help if you provided an actual schema and data (excluding irrelevant columns).
This table is self-referencing to make things easier for demo.
CREATE TABLE sample
(
id int AUTO_INCREMENT NOT NULL,
parent_id INT NULL,
stock int NOT NULL,
PRIMARY KEY (`id`),
CONSTRAINT FOREIGN KEY (`parent_id`) REFERENCES `sample` (`id`)
);
And here's some sample data. There are two records that are "root" and don't have parent values (IDs 1 and 5), two child values (IDs 2 and 3) and one grandchild value (ID 4)
INSERT INTO sample VALUES (1, null, 11);
INSERT INTO sample VALUES (2, 1, 22);
INSERT INTO sample VALUES (3, 1, 33);
INSERT INTO sample VALUES (4, 2, 4);
INSERT INTO sample VALUES (5, null, 55);
Finite/bound
If you have a finite/bound depth, you can make use of subqueries like the below. This one goes to a depth of 3 and sums to 70. Hopefully it is fairly easy to read, but I've included a couple of comments.
SELECT
s.id,
s.stock -- root
+
(
(
SELECT
SUM(c.stock) -- child
FROM
sample c
WHERE
c.parent_id = s.id
)
+
(
SELECT
SUM(p.stock) -- grandchild
FROM
sample c
JOIN
sample p
ON
p.parent_id = c.id
WHERE
c.parent_id = s.id
)
)
as three_level_sum
FROM
sample s
WHERE
s.id = 1;
Infinite/unbound
If you have an infinite hierarchy, however, things get more complicated. MySQL and other database platforms have a thing called "Common Table Expressions" (CTEs) that allow you to make recursive queries. These can be harder to wrap your head around because of the recursion, but it basically does the same as the previous version, just with infinite depth. This version also returns the sum of 70.
WITH RECURSIVE sample_rec AS
(
SELECT
id AS root_id,
id,
parent_id,
stock
FROM
sample
WHERE
parent_id IS NULL
UNION ALL
SELECT
R.root_id,
E.id,
E.parent_id,
E.stock
FROM
sample E
INNER JOIN
sample_rec R
ON
E.parent_id = R.id
)
SELECT
SUM(stock)
FROM
sample_rec
WHERE
root_id = 1
I have a table with three columns, I want copy/paste all three columns within the same table, however, of the three columns, I want to update two columns with new data specific for that day while keeping one column the same. For the following table:
ticket_number | book_id | log_id
------------- | ------- | ------
1 | 1 | 120
12 | 2 | 120
23 | 3 | 120
I want to:
1) Copy all columns and paste into the same table
2) change the ticket_number column with new data for that day (e.g. 2, 13, 25) as well as the log_id column with the id for the current day (e.g. 121), while keeping book_id column the same.
I have tried with no avail:
INSERT INTO ticket (ticket_number, book_id, log_id) SELECT (2,13,24), (book_id), (121) FROM ticket;
This the schema for reference
Your SELECT query needs to return the rows that you want to insert.
UPDATE: You can use a separate table, which might be easier. Something like this:
CREATE TABLE id_map (
old_ticket_number NUMBER,
new_ticket_number NUMBER
);
You could insert the values into this table.
You can then use this query:
INSERT INTO ticket (ticket_number, book_id, log_id)
SELECT
m.new_ticket_number,
t.book_id,
121
FROM ticket t
INNER JOIN id_map m ON t.ticket_number = m.old_ticket_number;
Does this so what you're looking for?
I have a table like below:
'table_a'
Type | Value
-----+------------
000 | 100020003
001 | 004
002 | 5000600070008
I need to end up with a result set that is like below:
'table_b'
---+---+---+---
1 | 2 | 3 | 4 ETC...
I have used substring to pull 1, 2, and 3 where type = 000. Now I need to do the same with type 001 and 002 but how can they be joined together to create one row in 'table_b'?
So far I have used the below to populate 1, 2 and 3 but I have no idea how to select the data from the remaining rows.
SELECT SUBSTRING(Value,1,1) AS val_1
SUBSTRING(Value,5,1) AS val_2
SUBSTRING(Value,9,1) AS val_3
FROM table_a
WHERE type = 000
Next query would be like this:
SELECT SUBSTRING(Value,3,1) AS val_4
FROM table_a
WHERE type = 001
So as you can see I cannot use a union because I am not selecting the same number of items in each select statement.
The data I am pulling from is not this uniform but hopefully this conveys what I need to do correctly. I greatly appreciate any assistance.
SELECT SUBSTRING(Value,1,1) || "val_1",
SUBSTRING(Value,5,1) || "val_2",
SUBSTRING(Value,9,1) || "val_3",
FROM table_a
WHERE type = 000
I have a table:
+--------+-------------------+-----------+
| ID | Name | Order |
+--------+-------------------+-----------+
| 1 | John | 1 |
| 2 | Mike | 3 |
| 3 | Daniel | 4 |
| 4 | Lisa | 2 |
| 5 | Joe | 5 |
+--------+-------------------+-----------+
The order can be changed by admin hence the order column. On the admin side I have a form with a select box Insert After: to entries to the database. What query should I use to order+1 after the inserted column.
I want to do this in a such way that keeps server load to a minimum because this table has 1200 rows at present. Is this the correct way to save an order of the table or is there a better way?
Any help appreciated
EDIT:
Here's what I want to do, thanks to itsmatt:
want to reorder row number 1 to be after row 1100, you plan to leave 2-1100 the same and then modify 1 to be 1101 and increment 1101-1200
You need to do this in two steps:
UPDATE MyTable
SET `Order` = `Order` + 1
WHERE `Order` > (SELECT `Order`
FROM MyTable
WHERE ID = <insert-after-id>);
...which will shift the order number of every row further down the list than the person you're inserting after.
Then:
INSERT INTO MyTable (Name, `Order`)
VALUES (Name, (SELECT `Order` + 1 FROM MyTable WHERE ID = <insert-after-id>));
To insert the new row (assuming ID is auto increment), with an order number of one more than the person you're inserting after.
Just add the new row in any normal way and let a later SELECT use ORDER BY to sort. 1200 rows is infinitesimally small by MySQL standards. You really don't have to (and don't want to) keep the physical table sorted. Instead, use keys and indexes to access the table in a way that will give you what you want.
you can
insert into tablename (name, `order`)
values( 'name', select `order`+1 from tablename where name='name')
you can also you id=id_val in your inner select.
Hopefully this is what you're after, the question isn't altogether clear.
I have a pair of tables and I need to search for numeric values in Table1 that match associated IDs on Table2. For example:
Table1
ID | Item
1 Cat
3 Frog
9 Dog
11 Horse
Table2
Category | Contains
Group 1 1
Group 2 3|9
Group 3 3|9|11
Originally I was thinking a LIKE would work, but if I searched for "1", I'd end up matching "11". I looked into SETs, but the MySQL docs state that the maximum number of elements is 64 and I have over 200 rows of items in Table1. I could wrap each item id with a character (e.g. "|1|") but that doesn't seem very efficient. Each Group will have unique items (e.g., there won't be two Cats in the same Group).
I found a similar topic as my problem and one of the answers suggested making another table, but I don't understand how that would work. A new table containing what, exactly?
The other option I have is to split the Contains into 6 separate columns, since there's never going to be more than 6 items in a Group, but then I'm not sure how to search all 6 columns without relying on six OR queries:
Category | C1 | C2 | C3 | C4 (etc)
Group 1 1 null null null
Group 2 3 9 null null
Group 3 3 9 11 null
SELECT * FROM Table2 WHERE C1 = '1' OR C2 = '1' OR C3 = '1' etc.
I'm not sure what the most efficient way of handling this is. I could use some advice from those with more experience with normalizing this kind of data please. Thank you.
I think it'd be best to create another table to normalize your data, however what you're proposing is not exactly what I'd suggest.
Realistically what you are modeling is a many-to-many relationship between table1 and table2. This means that one row in table1 can be associated with many rows in table2, and vice versa.
In order to create this kind of relation, you need a third table, which we can call rel_table1_table2 for now.
rel_table1_table2 will contain only primary key values from the two associated tables, which in this case seem to be table1.ID and table2.Category.
When you want to associate a row in table1 with a row in table2, you'd add a row to rel_table1_table2 with the primary key values from table1 and table2 respectively.
Example:
INSERT INTO rel_table1_table2 (ID, Category) VALUES (1, "Group 1")
When you need to find out what Items belong to a Category, you'd simply query your association table, for example:
SELECT i.Item from table1 t1 join rel_table1_table2 r on t1.ID=r.ID join table2 t2 on r.Category=t2.Category WHERE t2.Category="Group 3"
Does that make sense?
That "new" table would contain one row for each category an animal belongs to.
create table animal(
animal_id
,name
,primary key(animal_id)
)
create table category(
category_id
,name
,primary key(category_id)
)
create table animal_categories(
animal_id
,category_id
,primary key(animal_id, category_id)
)
For your example data, the animal_categories table would contain:
category_id | animal_id
+-----------+------------+
| 1 | 1 |
| 2 | 3 |
| 2 | 9 |
| 3 | 3 |
| 3 | 9 |
| 3 | 11 |
+-----------+------------+
Instead of using "like" use "REGEXP" so that you don't get "11" when looking for "1"
Break Table2.Contains in another table which joins Item and Category:
Item Item_Category Category
------ -------------- ---------
ID (1)----(*)ItemID Name
Name CategoryID(*)-------(1) ID
Now, your query will look like:
SELECT Category.* FROM Category, Item_Category
WHERE (Item_Category.CategoryID = Category.ID)
AND (Item_Category.ItemID IN (1, 2, 3, 11))
It seems like your problem is the way you are using the rows in Table 2. In databases it should always trigger a red flag when you find yourself using a list of values in a row.
Rather than having each category be in a single row in table 2, how about using the same category in multiple rows, with the Contains column only storing a single value. Your example could be changed to:
Table 1
ID | Item
1 Cat
3 Frog
9 Dog
11 Horse
Table 2
Category | Contains
Group 1 1
Group 2 3
Group 2 9
Group 3 3
Group 3 9
Group 3 11
Now when you want to find out "What items does group 2 contain?", you can write a query for that which selects all of the "Group 2" category rows from Table 2. When you want to find out, "What is the name of item 9", you can write a query that selects a row from Table 1.