Getting the highest number from a mysql query - mysql

My issue is I need to create an order so I can move items up and down in this web application. However, I can not index the order(ord column) values by an index with an incremental value because there are several companies in the same table that use this column.
My table structure is this:
Right now I am thinking that the easiest way would be to do a MAX and grab the highest number and use that as an index in a way so you never end up with the same number twice for a specific companies listing when you go to add a new entry for a company.
SELECT MAX(ord) FROM phonebook WHERE `id_company` = "51";
Would this be a wise route to go? OR maybe create a new database for each client and create and index and use that as a way order entries?

I suggest you aim for less than complete perfection in your assignment of ord values. You can get away with this as follows:
don't make ord unique. (It isn't).
rely on the ordering of phonebook_name to get a good order of names. MySQL has these wonderful case-insensitive collations for precisely this purpose.
I suppose you're trying to make some of the entries for a company come first, and others come last. Set the ord column to 50 for everybody, then give the entries you want first lower numbers, and the ones you want last higher numbers.
When you display data for a particular company, do it like this ...
SELECT whatever, whatever
FROM phonebook
WHERE id_company = 11
ORDER BY ord, phonebook_name, phonebook_number, id_phonebook
This ORDER BY clause will do what you want, and it will be stable if there are duplicates. You can then, in your user interface, move an entry up with a query like this.
UPDATE phonebook SET ord=ord-1 WHERE id_phonebook = :recordnumber

Related

SQL only get rows that matches full number split by a comma

I'm working on something that shows shops under a specific category, however I have an issue because I store the categories of a shop like this in a record with the id of a category. "1,5,12". Now, the problem is if I want to show shops with category 2, it "mistakens" 12 as category 2. This is the SQL right now.
SELECT * FROM shops WHERE shop_cats LIKE '%".$sqlid."%' LIMIT 8
Is there a way to split the record "shop_cats" by a comma in SQL, so it checks the full number? The only way I can think of is to get all the shops, and do it with PHP, but I don't like that as it will take too many resources.
This is a really, really bad way to store categories, for many reasons:
You are storing numbers as strings.
You cannot declare proper foreign key relationships.
A (normal) column in a table should have only one value.
SQL has poor string functions.
The resulting queries cannot take advantage of indexes.
The proper way to store this information in a database is using a junction table, with one row per shop and per category.
Sometimes, we are stuck with other people's really bad design decisions. If this is your case, then you can use FIND_IN_SET():
WHERE FIND_IN_SET($sqlid, shop_cats) > 0
But you should really fix the data structure.
If you can, the correct solution should be to normalize the table, i.e. have a separate row per category, not with commas.
If you can't, this should do the work:
SELECT * FROM shops WHERE CONCAT(',' , shop_cats , ',') LIKE '%,".$sqlid.",%' LIMIT 8
The table shops does not follow 1NF (1st Normal Form) i.e; every column should exactly one value. To avoid that you need to create another table called pivot table which relates two tables (or entities). But to answer your question, the below SQL query should do the trick.
SELECT * FROM shops WHERE concat(',',shop_cats,',') LIKE '%,".$sqlid.",%' LIMIT 8

The best/correct way in MySql to group records (not "Group By")

I have a table that is going to have a bunch of stock numbers and some other information. I need to be able to create groups of stock numbers e.g. products 123A,456B, and 789C all are in the same group. Each stock number has its own record in the table. I don't really care how it is accomplished so long as I can make sure that the items are grouped and that group numbers are unique. What is the best way to accomplish this?
There are a few ways I can think of to accomplish this but I'm not really sure what the best way is or if there are hidden drawbacks:
1) I could have a separate table with one auto increment column that is responsible for generating group id's and then add the Id to the stock number table once it's generated but that semes wasteful.
2) Would selecting the max groupId from the stock number table and adding one to it be good to get new group id's?
3) I could not have groupId in the stock number table and do it using a separate table with a GroupID column and a StockNumberId column. Still how would I get the groupId doing it this way?
You don't have to respond to all three. In indication of which would be the most appropriate way and any notes on implementation or pitfalls would be helpful. Also if there is a better way I did not innumerate please enlighten me. Thank you.
If you only need to set a groupId for each stock, and if each stock belongs to one and only one group then solution (2) would work just fine.
I would also create an index on the groupId column for easy retrieval of stocks that belong to the same group, as well as for getting the MAX(groupId) more efficiently.
I would use solution (1) if I had to also store group information, e.g., groupName, etc.
Solution (3) would be more towards a Many-To-Many relation between Stocks and Groups where the table you are describing sits in between the two. But in your case this would not be a good solution.

MySQL Query eliminate duplicates but only adjacent to each other

I have the following query..
SELECT Flights.flightno,
Flights.timestamp,
Flights.route
FROM Flights
WHERE Flights.adshex = '400662'
ORDER BY Flights.timestamp DESC
Which returns the following screenshot.
However I cannot use a simple group by as for example BCS6515 will appear a lot later in the list and I only want to "condense" the rows that are the same next to each other in this list.
An example of the output (note BCS6515 twice in this list as they were not adjacent in the first query)
Which is why a GROUP BY flightno will not work.
I don't think there's a good way to do so in SQL without a column to help you. At best, I'm thinking it would require a subquery that would be ugly and inefficient. You have two options that would probably end up with better performance.
One would be to code the logic yourself to prune the results. (Added:) This can be done with a procedure clause of a select statement, if you want to handle it on the database server side.
Another would be to either use other information in the table or add new information to the table for this purpose. Do you currently have something in your table that is a different value for each instance of a number of BCS6515 rows?
If not, and if I'm making correct assumptions about the data in your table, there will be only one flight with the same number per day, though the flight number is reused to denote a flight with the same start/end and times on other days. (e.g. the 10a.m. from NRT to DTW is the same flight number every day). If the timestamps were always the same day, then you could use DAY(timestamp) in the GROUP BY. However, that doesn't allow for overnight flights. Thus, you'll probably need something such as a departure date to group by to identify all the rows as belonging to the same physical flight.
GROUP BY does not work because 'timestamp' value is different for 2 BCS6515 records.
it will work only if:
SELECT Flights.flightno,
Flights.route
FROM Flights
WHERE Flights.adshex = '400662'
GROUP BY (Flights.flightno)

I need some sort of full text search on mysql database

I've stuck with one quite tricky problem.
I have list of products from different warehouses, where each product have: Brand and Model plus some extra details. Model could be quite different from different warehouses for the same product, but Brand is always the same.
All list of products I store in one table, let's say it will be Product table.
Then I have another table - Model, with CORRECT Model Name, Brand and additional details like image, description etc. Plus I have keywords column where I try to add all keywords manually.
And here is the problem, I need to associate each product that I receive from warehouse with one record from my Model table. Right now I'm using full text search in boolean mode, but that's quite painful and does not work very well. I need to do a lot of manual work.
Here are just few examples of names that I have:
WINT.SPORT3D
WINT.SPORT3D XL
WINT.SPORT 3D
WINT.SPORT3D MO
WINTER SPORT 3D
The correct name for all of these items would be: WINTER SPORT 3D, so they should all be assigned to the same model.
So, is there any way to improve full text search or some other technique to solve my problem?
Database that I'm using is MySQL, I would prefer not to change it.
I'll start by putting together a more formal definition of the tables:
warehouse:
warehouse_id,
warehouse_product_id,
product_brand,
product_name,
local_id
Here I'd using local_id as a foreign key to your 'Model' table - but to avoid further confusion, I'll call it 'local'
local:
id,
product_brand,
product_name
It seems like the table you describe as 'product' is redundant.
Obviously until the data is cross referenced, local_id will be null. But after it is populated it won't have to change, and given a warehouse_id, a band and a product, you can find your local descriptor easily:
SELECT local.*
FROM local, warehouse
WHERE local.id=warehouse.local_id
AND warehouse.product_brand=local.product_brand
AND warehouse_id=_____
AND warehouse.product_brand=____
AND warehouse.product_name=____
So all you need to do is populate the links. Soundex is a rather crude tool - a better solution for this would be the Levenstein distance algorithm. There's a mysql implementation here
Given a set of rows in the warehouse table which need to be populated:
SELECT w.*
FROM warehouse w
WHERE w.local_id IS NULL;
...for each row identify the best match as (using the values from the previous query as w.*)....
SELECT local.id
FROM local
WHERE local.product_brand=w.product_brand
ORDER BY levenstein(local.product_name, w.product_name) ASC
LIMIT 0,1
But this will find the best match, even if the 2 strings are completely different! Hence....
SELECT local.id
FROM local
WHERE local.product_brand=w.product_brand
AND levenstein(local.product_name, w.product_name)<
(IF LENGTH(local.product_name)<LENGTH(w.product_name),
LENGTH(local.product_name), LENGTH(w.product_name))/2
ORDER BY levenstein(local.product_name, w.product_name) ASC
LIMIT 0,1
...requires at least half the string to match.
So this can be implemented in a single update statement:
UPDATE warehouse w
SET local_id=(
SELECT local.id
FROM local
WHERE local.product_brand=w.product_brand
AND levenstein(local.product_name, w.product_name)<
(IF LENGTH(local.product_name)<LENGTH(w.product_name),
LENGTH(local.product_name), LENGTH(w.product_name))/2
ORDER BY levenstein(local.product_name, w.product_name) ASC
LIMIT 0,1
)
WHERE local_id IS NULL;
Try Soundex. All of your examples resolve to W532 while the last one resolves to W536. So, you could:
Add a column to PRODUCT and MODEL called SoundexValue and calculate the Soundex value for each product and model
Compare the Soundex values in the PRODUCT table to the ones in the Model Table. You may have to use a range (+/- 5) to get a higher rate of matching.
Follow the 80/20 rule. That is, spend 80% of your manual effort on the 20% that don't easily fall out.

Mysql Insert data into table have a arranges question?

I found a weard problem with my MySQL DB.
sometime when I insert new data into it, the way it arranges the data is like a stack, for example
4 (newest)
3
2
1 (oldest)
...
how can I make it arranged like this?
1 (newest)
2
3
4 (oldest)
thanks all.
SELECT *
FROM TABLE
ORDER BY ID
You have to remember that when viewing/selecting data from a table without any ORDER BY specified does not garuantee any specific order.
The way you are view the data (unordered) can be due to any one of a lot of factos (the database engine, schema, page storage, page fragmentation, indexes, primary keys, or simply execution plan optimization).
The SQL standards specifically states that tables do not have a "natural" order. Therefore, the database engine is free to return a request without an ORDER BY in any order it wants to. The order may change from one request to another because most engines choose to return the data in whatever order they can get it to you the most rapidly.
It follows, therefore, that if you want the data out in a particular order you must include a column in your table whose job is to proxy for the order in which you added records to the table. Two common ways of doing this are using an autoincrement field which will be in numerical order from oldest to newest record, and a TIMESTAMP column which does just what it says. Once you have such a column you can use ORDER BY ColumnName when searching to get an ordered result set.