Mysql calculation with multiple summands not working - mysql

I have a query on two columns from two different tables (connected by a left join in my query) and I want to order the search results by the occurence of the term I am looking for. I came up with this as my sorting variable in the statement, which might not be elegant, but works fine:
((LENGTH(table1.column)-LENGTH(REPLACE(lower(table1.column),lower('$term'),'')))/LENGTH('$term') AS sort_frequency
$term is my search term and at the end of the query I do this: ORDER BY sort_frequency DESC.
Now comes the difficulty: the calculation works fine for both tables separately, but when I want to connect the two by addition, the results of table2 always come in front of the results of table1 and nothing is ordered by occurence. My statement looks like this:
(((LENGTH(table1.column)-LENGTH(REPLACE(lower(table1.column),lower('$term'),'')))/LENGTH('$term')) + ((LENGTH(table2.column)-LENGTH(REPLACE(lower(table2.column),lower('$term'),'')))/LENGTH('$term'))) AS sort_frequency
I need this calculation, because the search results come from two different tables, but shall be ordered together on one page (let's say: one table is about images with certain keywords and the second table is about videos with certain keywords, once I searched for a specific keyword I don't care whether it is an image or video, I want the one that fits my keyword query most).
Do you have any idea why the calculation does not work? What is my mistake? I have tried adding/removing brackets, but that does not help.
Any help would be appreciated,

Have you tried using a UNION to combine the two table before searching for occurrences? My Suggestion is to use something along the lines of:
SELECT((LENGTH(newcolumn)-LENGTH(REPLACE(lower(newcolumn),lower('$term'),'')))/LENGTH('$term') AS sort_frequency FROM table1.column UNION table2.column AS newcolumn

Related

In MySQL is there a way to chose one column over another when doing SELECT *?

Ok, for a moment, throw out of your mind "good database design". Let's say I have two tables, and they have some of the same columns.
item
-------
id
title
color
and
item_detail
-------
id
weight
color
In a good normal query, you'd choose the columns you want within the query, like so:
SELECT item.title, item_detail.color, item_detail.weight ...
But what if you are stuck with a query that was built with star/all:
SELECT * ...
In this case you would get two color columns pulled back in your results, one for each table. Is there a way in MySQL to chose one color column over the other, so only one shows up in the results, without a full rewrite of the statement? So that I could say that the table item_detail takes priority?
Probably not but I thought I'd ask.
Err. No there is not.
But define "without a full rewrite of the statement". As far as I can see you'd just need to rewrite the select * portion of the query.
If you cannot touch the statement at all, then you are free to ignore the column in your application (the order of the columns does not change between calls)... or you could create a view...
It's hard to know which constraints you are dealing with when you say "But what if you are stuck with a query".

Mysql Find if one column values are partially present in multiple rows

I have a Mysql table which contains the subjects of emails. It has 2 columns, id and title. Some subjects might contain Re:, some might contain Fwd: and so on. I would like to write a query which returns rows where the value of the title of one row is contained in some other row. It is not necessarily an exact match but like finding a haystack in the needle. I have tried multiple ways like using sub queries or self join, but to no success. Any help will be appreciated. Thanks in advance.

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

is there an "inverse" function to IN() in MySQL?

The scenario is this: in a table A, I have one column "tags", which is varchar(255).
In this column I store numbers, separated by commas, like this:
2,14,31,33,56
etc. there can be none, one, or several.
and I need to make a SELECT query that will return rows that have a certain number in this field. right now I'm using this method (don't be alarmed, I know its a poor way.. that's why I'm asking for help!). for example, let's assume the number I want to check is 33. the query is:
SELECT * FROM table_a WHERE
tags LIKE "%,33,%" OR tags LIKE "33,%" OR tags LIKE "%,33" OR tags LIKE "33"
I'm no expert but I know this can't be the method. The first question that comes to mind is: is there a command similar to IN() but that works the other way around?
I mean, can I tell it "find rows where 'tags' contains value 33" ?
When asking this question, I can see that there may be another field type other than varchar(255) to contain this type of data (an array of numbers, after all)
Is there a GOOD and efficient way of doing this? my method works for small tables, yes, but if the table grows.. (say, 10k rows, 50k, 300k ... ) this is obviously a problem.
The function that you want is find_in_set():
SELECT *
FROM table_a
WHERE find_in_set(33, tags) > 0;
You can simplify your like statement to be:
SELECT *
FROM table_a
WHERE concat(',', tags, ',') LIKE '%,33,%';
Neither of these can make use of an index. Having a separate table with one row per entity and per tag is the right way to go (but I think you know this already).

Selecting rows based on duplicate values

I basically have results grid and i have a drop down menu on my application which filters the 'Carrier' column. But when selecting a certain carrier I want all the rows returned that have the same dr_id as the Carrier which has been selected.
For example if you look at the picture attached it shows my results grid. If I filter by carrier 'ACE CALL LTD_UK' then I want rows 27, 28, 29 and 30 returned because the dr_id is the same.
Thanks
I don't have a complete solution for you as I don't know exactly what you database schema is (and it is a large stored procedure!). However I do have some suggestions/comments which you might find helpful:
I assume that the stored procedure will currently be returning a single row when they filter is set to 'ACE CALL LTD_UK', if not then this might not be relevant!
What I would do in this case would be to take you SELECT statement and put the results into a CTE, temporary table or nested query. (I'm not sure what SQL DBMS your using, looks like MSSQL, but you also have a MySQL tag for you post).
Once I have those results I would then use a LEFT JOIN from the dr_id in the temp table back to the drm table on the same column. From here you will again need to join to other tables where the data is not distinct, for example the Carrier table, then select the columns that you require.
You could do all this in the existing SELECT statement, however you will have to start joining on tables multiple times or use nested queries, which would get very messy. However the main reason why I chose the solution I have posted is because I don't know the stored procedure well enough and therefore I chose the safest solution.
If you want an example of what I mean, I will try and provide one.