I have two tables, with different columns that I would like to compare. There is an issue in our system with serial numbers, and I want to make sure that all of the serial numbers (CMMTTEXT - in comma delimitted form) in Table B are being transferred to Table A (SERLTNUM - where each individual serial number has its own line)
Basically, what I would like to try and do is take the SOPNUMBER's from the last 3 months (which I would get from Table C), then get all rows from Table B and Table A with the last 3 months SOPNUMBER's and then somehow to make sure all serial numbers in CMMTTEXT in Table B are in Table A as SERLTNUM.
I know how to get all of the data, but I'm not sure what I can do in order to compare the two columns in SQL when they have different data formats. I am trying to think if there is someway I can just use substr() to search CMMTTXT but don't know how I could then display rows where there was no match found.
The LNITMSEQ table is an ID that corresponds to different line items in an order.
Table A
+-----------+----------+----------+---------------+
| SOPNUMBER | LNITMSEQ | SERLTNUM | ITEMNMBR |
+-----------+----------+----------+---------------+
| I327478 | 16384 | ABC123 | someItem |
+-----------+----------+----------+---------------+
| I327478 | 32768 | DEF123 | someOtherItem |
+-----------+----------+----------+---------------+
Table B
+-----------+----------+-----------------------------+
| SOPNUMBER | LNITMSEQ | CMMTTEXT |
+-----------+----------+-----------------------------+
| I327478 | 16384 | ABC123,ABC124,ABC125,ABC126 |
+-----------+----------+-----------------------------+
| I327478 | 32768 | DEF123,DEF124,DEF125,DEF126 |
+-----------+----------+-----------------------------+
Table C
+-----------+-----------+
| SOPNUMBER | DATE |
+-----------+-----------+
| I327478 | 5/20/2017 |
+-----------+-----------+
| I327479 | 5/21/2017 |
+-----------+-----------+
I have commented above, but a clearer answer can be found here for what you need:
SQL split values to multiple rows
You can use FIND_IN_SET function like as follows
SELECT * FROM TableA INNER JOIN TAableB
ON FIND_IN_SET(TableA.SERLTNUM, TableB.CMMTTEXT) > 0
FIND_IN_SET function returns a value in the range of 1 to N if the string str is in the string list strlist consisting of N substrings. for more detail see the manual
Related
In short; we are trying to return certain results from one table based on second level criteria of another table.
I have a number of source data tables,
So:
Table DataA:
data_id | columns | stuff....
-----------------------------
1 | here | etc.
2 | here | poop
3 | here | etc.
Table DataB:
data_id | columnz | various....
-----------------------------
1 | there | you
2 | there | get
3 | there | the
4 | there | idea.
Table DataC:
data_id | column_s | others....
-----------------------------
1 | where | you
2 | where | get
3 | where | the
4 | where | idea.
Table DataD: etc. There are more and more will be added ongoing
And a relational table of visits, where there are "visits" to some of these other data rows in these other tables above.
Each of the above tables holds very different sets of data.
The way this is currently structured is like this:
Visits Table:
visit_id | reference | ref_id | visit_data | columns | notes
-------------------------------------------------------------
1 | DataC | 2 | some data | etc. | so this is a reference
| | | | | to a visit to row id
| | | | | 2 on table DataC
2 | DataC | 3 | some data | etc. | ...
3 | DataB | 4 | more data | etc. | so this is a reference
| | | | | to a visit to row id
| | | | | 4 on table DataB
4 | DataA | 1 | more data | etc. | etc. etc.
5 | DataA | 2 | more data | etc. | you get the idea
Now we currently list the visits by various user given criteria, such as visit date.
however the user can also choose which tables (ie data types) they want to view, so a user has to tick a box to show they want data from DataA table, and DataC table but not DataB, for example.
The SQL we currently have works like this; the column list in the IN conditional is dynamically generated from user choices:
SELECT visit_id,columns, visit_data, notes
FROM visits
WHERE visit_date < :maxDate AND visits.reference IN ('DataA','DataC')
The Issue:
Now, we need to go a step beyond this and list the visits by a sub-criteria of one of the "Data" tables,
So for example, DataA table has a reference to something else, so now the client wants to list all visits to numerous reference types, and IF the type is DataA then to only count the visits if the data in that table fits a value.
For example:
List all visits to DataB and all visits to DataA where DataA.stuff = poop
The way we currently work this is a secondary SQL on the results of the first visit listing, exampled above. This works but is always returning the full table of DataA when we only want to return a subset of DataA but we can't be exclusive about it outside of DataA.
We can't use LEFT JOIN because that doesn't trim the results as needed, we can't use exclusionary joins (RIGHT / INNER) because that then removes anything from DataC or any other table,
We can't find a way to add queries to the WHERE because again, that would loose any data from any other table that is not DataA.
What we kind of need is a JOIN within an IF/CASE clause.
Pseudo SQL:
SELECT visit_id,columns, visit_data, notes
FROM visits
IF(visits.reference = 'DataA')
INNER JOIN DataA ON visits.ref_id = DataA.id AND DataA.stuff = 'poop'
ENDIF
WHERE visit_date < 2020-12-06 AND visits.reference IN ('DataA','DataC')
All criteria in the WHERE clause are set by the user, none are static (This includes the DataA.stuff criteria too).
So with the above example the output would be:
visit_id | reference | ref_id | visit_data | columns | notes
-------------------------------------------------------------
1 | DataC | 2 | some data | etc. |
2 | DataC | 3 | some data | etc. |
5 | DataA | 1 | more data | etc. |
We can't use Union because the different Data tables contain lots of different details.
Questions:
There may be a very straightforward answer to this but I can't see it,
How can we approach trying to achieve this sort of partial exclusivity?
I suspect that our overarching architecture structure here could be improved (the system complexity has grown organically over a number of years). If so, what could be a better way of building this?
What we kind of need is a JOIN within an IF/CASE clause.
Well, you should know that's not possible in SQL.
Think of this analogy to function calls in a conventional programming language. You're essentially asking for something like:
What we need is a function call that calls a different function depending on the value you pass as a parameter.
As if you could do this:
call $somefunction(argument);
And which $somefunction you call would be determined by the function called, depending on the value of argument. This doesn't make any sense in any programming language.
It is similar in SQL — the tables and columns are fixed at the time the query is parsed. Rows of data are not read until the query is executed. Therefore one can't change the tables depending on the rows executed.
The simplest answer would be that you must run more than one query:
SELECT visit_id,columns, visit_data, notes
FROM visits
INNER JOIN DataA ON visits.ref_id = DataA.id AND DataA.stuff = 'poop'
WHERE visit_date < 2020-12-06 AND visits.reference = 'DataA';
SELECT visit_id,columns, visit_data, notes
FROM visits
WHERE visit_date < 2020-12-06 AND visits.reference = 'DataC';
Not every task must be done in one SQL query. If it's too complex or difficult to combine two tasks into one query, then leave them separate and write code in the client application to combine the results.
In my table I have two columns "sku" and "fitment". The sku represents a part and the fitment represents all the vehicles this part will fit on. The problem is, in the fitment cells, there could be up to 20 vehicles in there, separated by ^^. For example
**sku -- fitment**
part1 -- Vehichle 1 information ^^ vehichle 2 information ^^ vehichle 3 etc
I am looking to split the cells in the fitment column, so it would look like this:
**sku -- fitment**
part1 -- Vehicle 1 information
part1 -- Vehicle 2 information
part1 -- Vehicle 3 information
Is this possible to do? And if so, would a mySQL db be able to handle hundreds of thousands of items "splitting" like this? I imagine it would turn my db of around 250k lines to about 20million lines. Any help is appreciated!
Also a little more background, this is going to be used for a drill down search function so I would be able to match up parts to vehicles (year, make, model, etc) so if you have a better solution, I am all ears.
Thanks
Possible duplicate of this: Split value from one field to two
Unfortunately, MySQL does not feature a split string function. As in the link above indicates there are User-defined Split function's.
A more verbose version to fetch the data can be the following:
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(fitment, '^^', 1), '^^', -1) as fitmentvehicle1,
SUBSTRING_INDEX(SUBSTRING_INDEX(fitment, '^^', 2), '^^', -1) as fitmentvehicle2
....
SUBSTRING_INDEX(SUBSTRING_INDEX(fitment, '^^', n), '^^', -1) as fitmentvehiclen
FROM table_name;
Since your requirement asks for a normalized format (i.e. not separated by ^^) to be retrieved, it is always better to store it in that way in the first place. And w.r.t the DB size bloat up, you might want to look into possibilities of archiving older data and deleting the same from the table.
Also, you should partition your table using an efficient partitioning strategy based on your requirement. It would be more easier to archive and truncate a partition of the table itself, instead of row by row.
E.g.
DROP TABLE IF EXISTS my_table;
CREATE TABLE my_table (user_id INT NOT NULL PRIMARY KEY,stuff VARCHAR(50) NOT NULL);
INSERT INTO my_table VALUES (101,'1,2,3'),(102,'3,4'),(103,'4,5,6');
SELECT *
FROM my_table;
+---------+-------+
| user_id | stuff |
+---------+-------+
| 101 | 1,2,3 |
| 102 | 3,4 |
| 103 | 4,5,6 |
+---------+-------+
SELECT * FROM ints;
+---+
| i |
+---+
| 0 |
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
| 6 |
| 7 |
| 8 |
| 9 |
+---+
SELECT DISTINCT user_id
, SUBSTRING_INDEX(SUBSTRING_INDEX(stuff,',',i2.i*10+i1.i+1),',',-1) x
FROM my_table
, ints i1
, ints i2
ORDER
BY user_id,x;
+---------+---+
| user_id | x |
+---------+---+
| 101 | 1 |
| 101 | 2 |
| 101 | 3 |
| 102 | 3 |
| 102 | 4 |
| 103 | 4 |
| 103 | 5 |
| 103 | 6 |
+---------+---+
I need help with a Query, i have a table like this:
| ID | codehwos |
| --- | ----------- |
| 1 | 16,17,15,26 |
| 2 | 15,32,12,23 |
| 3 | 53,15,21,26 |
I need an outpout like this:
| codehwos | number_of_this_code |
| -------- | ---------------------- |
| 15 | 3 |
| 17 | 1 |
| 26 | 2 |
I want to sum all the time a code is used in a row.
Can anyone make a query for doing it for all the code in one time?
Thanks
You have a very poor data format. You should not store lists in strings and never store lists of numbers in strings. SQL has a great data structure for storing lists. Hint: it is called a "table" not a "string".
That said, sometimes one is stuck with other people's really poor design choices. We wouldn't make them ourselves, but we still need to get something done. Assuming you have a list of codes, you can do what you want with:
select c.code, count(*)
from codes c join
table t
on find_in_set(c.code, t.codehwos) > 0
group by c.code;
If you have any influence over the data structure, then advocate for a junction table, the right way to store this data in a relational database.
I have two mysql tables as
Component
+----+-------------------------+--------+
| OldComponentId | NewComponentId |
+----+-------------------------+--------+
| 15 | 85 |
| 16 | 86 |
| 17 | 87 |
+----+-------------------------+--------+
Formulae
+----+-------------------------+--------+
| id | formula_string |
+----+-------------------------+--------+
| 1 | A+15-16+17 |
| 2 | 16+15-17 |
+----+-------------------------+--------+
I want to replace value of formula_string on the basis of NewComponentId as
Formulae
+----+-------------------------+--------+
| id | formula_string |
+----+-------------------------+--------+
| 1 | A+85-86+87 |
| 2 | 86+85-87 |
+----+-------------------------+--------+
I have tried with following mysql query but its not working
update Formulae fr, Component comp set formula_string=REPLACE(fr.formula_string,comp.OldComponentId,comp.NewComponentId).
Please suggest the solutions
thanks.
There is no easy way to do this. As you observed in your update statement, the replacements don't nest. They just replace one at a time.
One thing that you can do is:
update Formulae fr cross join
Component comp
set formula_string = REPLACE(fr.formula_string, comp.OldComponentId, comp.NewComponentId)
where formula_string like concat('%', comp.OldComponentId, '%')
Then continue running this until row_count() returns 0.
Do note that your structure could result in infinite loops (if A --> B and B --> A). You also have a problem of "confusion" so 10 would be replaced in 100. This suggests that your overall data structure may not be correct. Perhaps you should break up the formula into separate pieces. If they are just numbers and + and -, you can have a junction table with the value and the sign for each component. Then your query would be much easier.
I'm not very good at joining tables in mysql and I'm still learning,
So I wanted to ask, when joining two tables....
I have 2 tables
So for the first table I want to join the 2 of its columns (id & path) on the second table.
But on the second table there's no column name id and path, there is a column name pathid & value. The field of the pathid column is the same as the id.
it looks like this.
first table
| id | path |
---------------------
| 1 | country/usa |
| 2 | country/jpn |
| 3 | country/kor |
second table
| pathid | value |
-------------------
| 3 | 500 |
| 1 | 10000 |
| 2 | 2000 |
So on the first table, it indicates that for usa the id is 1, japan is 2, korea is 3.
And on the table it says that for pathid no. 3 ( which is the id for korea) the value is 500 and so on with the others.
I want it to look like this. So then the path will be joined on the second table on its corresponding value. How can I do this on mysql? Thank You
Desired Result
| id | path | value |
------------------------------
| 1 | country/usa | 10000 |
| 2 | country/jpn | 2000 |
| 3 | country/kor | 500 |
You can join on the columns irrespective of the column name as long as the data type match.
SELECT id, path, value
FROM firstTable, secondTable
WHERE id = pathid
If you have same column names on both tables then you need to qualify the name using alias. Say the column names for id were same on both tables then whenever you use id you should mention which table you are referring to. other wise it will complain about the ambiguity.
SELECT s.id, path, value
FROM firstTable f, secondTable s
WHERE f.id = s.pathid
Note that I ommited s. on other columns in select, it will work as long as the second table doesn't have columns with same name.