SQL join on returns none values - sql

// EDIT Found the problem. I changed all type from text to varchar. Now it works fine.
I have a table called "sounds" which looks like this:
rowID type int(11) | userID type text | name type text| soundfile type text
1 | "mod001:02" | "Jimmy" | "music/song.mp3"
and a table called "soundlist" which looks like this:
soundID type int(11) | name type text | soundfile type text | used type tinyint(1)
1 | "topSong" | "music/song.mp3" | 1
My problem is, when i'm run this query
SELECT *
FROM sounds
INNER JOIN soundlist
ON STRCMP(soundlist.soundfile, sounds.soundfile) = 0
WHERE STRCMP(sounds.userID, "mod001:02") = 0;
i'm getting an empty result!
My goal is to set "soundlist.used" to 0. I only have "sounds.userID" given.
I'm currently using this query:
UPDATE soundlist
INNER JOIN sounds
ON STRCMP(sounds.userID, "mod001:02") = 0
SET soundlist.used = 0
WHERE STRCMP(soundlist.soundfile, sounds.soundfile) = 0;

You can use nested queries :
UPDATE soundlist
set soundlist.used=0
where soundfile IN ( -- using IN keyword instead of = if you want to update multiple entries
select sounds.soundfile
from sounds
where sounds.rowID=1 -- or any other condition
);
I am assuming that rowID is an INT.
And if you want to go even further and don't bother comparing strings, why not using foreign keys ?
Let Sounds the same way :
rowID | userID | name | soundfile
1 | "mod001:02" | "Jimmy" | "music/song.mp3"
And modify sound list to reference sounds :
soundID | name | soundId | used
1 | "topSong" | 1 | 1
Your query :
SELECT *
FROM sounds
INNER JOIN soundlist
ON STRCMP(soundlist.soundfile, sounds.soundfile) = 0
WHERE STRCMP(sounds.userID, "mod001:02") = 0;
would become
SELECT *
FROM sounds s
INNER JOIN soundlist l
ON s.rowId=l.soundId
where STRCMP(s.userID, "mod001:02") = 0;
This saves you one STRCMP.
Consider using indexes on varchar columns used for conditions, it is faster and sometimes easier to read queries (s.userID = "mod001:02" is more straigthforward)

Edited: This will update sounds.userid to "0" where soundlist.used is "1"
UPDATE sounds
INNER JOIN soundlist ON
sounds.soundfile = soundlist.soundfile
SET sounds.userid = "0"
WHERE soundlist.used = "1"
If, instead you want the sounds.userid to equal soundlist.us
UPDATE sounds
INNER JOIN soundlist ON
sounds.soundfile = soundlist.soundfile
SET sounds.userid = soundlist.used

The problem is that you the text data type, if I use varchar the first query gets me the desired result set

Related

Use LIKE with multiple names from a different table in UPDATE

I'm looking to update a field to a different value if the string in name contains a value from a different table in PostgreSQL:
Table Types that needs to be updated
id | name | type
1 | Google Page | WEBSITE
2 | Yahoo Page | WEBSITE
3 | Facebook Page | WEBSITE
...
Table Companies that has the names
id | name
1 | Google
2 | Yahoo
3 | Facebook
4 | Twitter
5 | Stackoverflow
...
What I tried
UPDATE types
SET type = 'BUSINESS'
WHERE name LIKE CONCAT((SELECT companies.name from companies), '% Page')
But I'm getting this issue: [21000] ERROR: more than one row returned by a subquery used as an expression
You could use a subquery with exists logic to retain your current logic:
UPDATE types t
SET type = 'BUSINESS'
WHERE EXISTS (SELECT 1 FROM companies c
WHERE CONCAT(c.name, ' Page') = t.name);
You could also use an update join:
UPDATE types t
SET type = 'BUSINESS'
FROM companies c
WHERE t.name = CONCAT(c.name, ' Page');
You should use the IN directive:
WHERE name IN (SELECT CONCAT(companies.name, ' Page') name from companies)
Much cheaper than comparing concatenated strings:
UPDATE types t
SET type = 'BUSINESS'
FROM companies c
WHERE right(t.name, 5) = ' Page'
AND left(t.name, -5) = c.name;
db<>fiddle here

SQL - Multiple select filter: Combine filter conditions to get proper results

I'm working on a filter where the user can choose different conditions for the end output. Right now I'm doing the construction of the SQL query, but whenever more conditions are selected, it doesn't work.
Example of the advalues table.
+----+-----------+---------------+------------+
| id | listingId | value | identifier |
+----+-----------+---------------+------------+
| 1 | 1a | Alaskan Husky | race |
+----+-----------+---------------+------------+
| 2 | 1a | Højt | activity |
+----+-----------+---------------+------------+
| 3 | 1c | Akita | race |
+----+-----------+---------------+------------+
| 4 | 1c | Mellem | activity |
+----+-----------+---------------+------------+
As you can see, there's a different row for each advalue.
The outcome I expect
Let's say the user has checked/ticked the checkbox for the race where it says "Alaskan Husky", then it should return the listingId for the match (once). If the user has selected both "Alaskan Husky" and activity level to "Low" then it should return nothing, if the activity level is either "Mellem" or "Højt" (medium, high), then it should return the listingId for where the race is "Alaskan Husky" only, not "Akita". I hope you understand what I'm trying to accomplish.
I tried something like this, which returns nothing.
SELECT * FROM advalues WHERE (identifier="activity" AND value IN("Mellem","Højt")) AND (identifier="race" AND value IN("Alaskan Husky"))
By the way, I want to select distinct listingId as well, so it only returns unique listingId's.
I will continue to search around for solutions, which I've been doing for the past few hours, but wanted to post here too, since I haven't been able to find anything that helped me yet. Thanks!
You can split the restictions on identifier in two tables for each type. Then you join on listingid to obtain the listingId wich have the two type of identifier.
SELECT ad.listingId
FROM advalues ad
JOIN advalues ad2
ON ad.listingId = ad2.listingId
WHERE ( ad.identifier = 'activity' AND ad.value IN( 'Mellem', 'Højt' ) )
AND ( ad2.identifier = 'race' AND ad2.value IN( 'Alaskan Husky' ) )
The question isn't exactly clear, but I think you want this:
WHERE (identifier="activity" AND value IN("Mellem","Højt")) OR (identifier="race" AND value IN("Alaskan Husky"))
If I got you right you are trying to fetch data with different "filters".
Your Query
SELECT listingId FROM advalues
WHERE identifier="activity"
AND value IN("Mellem","Højt")
AND identifier="race"
AND value IN("Alaskan Husky")
Will always return 0 results as you are asking for identifier = "activity" AND identifier = "race"
I think you wanted to do something like this instead:
SELECT listingId FROM advalues
WHERE
(identifier="activity" AND value IN("Mellem","Højt"))
OR
(identifier="race" AND value IN("Alaskan Husky"))

magento: join product with attribute value

I'm trying to list some of my product from a php script and I need to get some attributes's value. For exemple I'm trying something like this::
Mage::app();
Mage::app()->setCurrentStore(1);
$collection = Mage::getModel('catalog/product')->getCollection()
->addAttributeToSelect('computer_type')
->joinAttribute('computer_type_value', 'eav/entity_attribute_option', "computer_type", null, 'left', 0)
"computer_type" from product collection store an id which is found in option_id field of the eav_attribute_option_value table:
+----------+-----------+----------+--------+
| value_id | option_id | store_id | value |
+----------+-----------+----------+--------+
| 3738 | 14 | 0 | server |
+----------+-----------+----------+--------+
I would like to join this table with my collection's result in order to have the value "server" displayed instead of the id "3738" but the way I'm doing it is not working and despite all my search.
I didn't find how to achieve that in only one query. Is it possible ?
Please use below code for join product attribute:
$mageFilename = 'app/Mage.php';
require_once $mageFilename;
umask(0);
Mage::app('admin');
Mage::register('isSecureArea', 1);
Mage::app()->setCurrentStore(Mage_Core_Model_App::ADMIN_STORE_ID);
$collection = Mage::getModel('catalog/product')
->getCollection()
->addAttributeToSelect('*')
->addAttributeToFilter('computer_type',array('neq'=>0))
->addAttributeToFilter('status', Mage_Catalog_Model_Product_Status::STATUS_ENABLED)
->addAttributeToFilter('visibility', Mage_Catalog_Model_Product_Visibility::VISIBILITY_BOTH);

MYSQL - Combining Two Results in One Query

I have a query I need to perform to show search results for a project. What needs to happen, I need to sort the results by the "horsesActiveDate" and this applies to all of them except for any ad with the adtypesID=7. Those results are sorted by date but they must always result after all other ads.
So I will have all my ads in the result set be ordered by the Active Date AND adtypesID != 7. After that, I need all adtypesID=7 to be sorted by Active Date and appended at the bottom of all the results.
I'm hoping to put this in one query instead of two and appending them together in PHP. The way the code is written, I have to find a way to get it all in one query.
So here is my original query which has worked great until I had to ad the adtypesID=7 which has different sorting requirements.
This is the query that exists now that doesn't take into account the adtypesID for sorting.
SELECT
horses.horsesID,
horsesDescription,
horsesActiveDate,
adtypesID,
states.statesName,
horses_images.himagesPath
FROM horses
LEFT JOIN states ON horses.statesID = states.statesID
LEFT JOIN horses_images ON horses_images.himagesDefault = 1 AND horses_images.horsesID = horses.horsesID AND horses_images.himagesPath != ''
WHERE
horses.horsesStud = 0
AND horses.horsesSold = 0
AND horses.horsesID IN
(
SELECT DISTINCT horses.horsesID
FROM horses
LEFT JOIN horses_featured ON horses_featured.horsesID = horses.horsesID
WHERE horses.horsesActive = 1
)
ORDER BY adtypesID, horses.horsesActiveDate DESC
My first thought was to do two queries where one looked for all the ads that did not contain adtypesID=7 and sort those as the query does, then run a second query to find only those ads with adtypesID=7 and sort those by date. Then take those two results and append them to each other. Since I need to get this all into one query, I can't use a php function to do that.
Is there a way to merge the two query results one after the other in mysql? Is there a better way to run this query that will accomplish this sorting?
The Ideal Results would be as below (I modified the column names so they would be shorter):
ID | Description | ActiveDate | adtypesID | statesName | himagesPath
___________________________________________________________________________
3 | Ad Text | 06-01-2010 | 3 | OK | image.jpg
2 | Ad Text | 05-31-2010 | 2 | LA | image1.jpg
9 | Ad Text | 03-01-2010 | 4 | OK | image3.jpg
6 | Ad Text | 06-01-2010 | 7 | OK | image5.jpg
6 | Ad Text | 05-01-2010 | 7 | OK | image5.jpg
6 | Ad Text | 04-01-2010 | 7 | OK | image5.jpg
Any help that can be provided will be greatly appreciated!
I am not sure about the exact syntax in MySQL, but something like
ORDER BY case when adtypesID = 7 then 2 else 1 end ASC, horses.horsesActiveDate DESC
would work in many other SQL dielects.
Note that most SQL dialects allow the order by to not only be a column, but an expression.
This should work:
ORDER BY (adtypesID = 7) ASC, horses.horsesActiveDate DESC
Use a Union to append two queries together, like this:
SELECT whatever FROM wherever ORDER BY something AND adtypesID!=7
UNION
SELECT another FROM somewhere ORDER BY whocares AND adtypesID=7
http://dev.mysql.com/doc/refman/5.0/en/union.html
I re-wrote your query as:
SELECT h.horsesID,
h.horsesDescription,
h.horsesActiveDate,
adtypesID,
s.statesName,
hi.himagesPath
FROM HORSES h
LEFT JOIN STATES s ON s.stateid = h.statesID
LEFT JOIN HORSES_IMAGES hi ON hi.horsesID = h.horsesID
AND hi.himagesDefault = 1
AND hi.himagesPath != ''
LEFT JOIN HORSES_FEATURED hf ON hf.horsesID = h.horsesID
WHERE h.horsesStud = 0
AND h.horsesSold = 0
AND h.horsesActive = 1
ORDER BY (adtypesID = 7) ASC, h.horsesActiveDate DESC
The IN subquery, using a LEFT JOIN and such, will mean that any horse record whose horsesActive value is 1 will be returned - regardless if they have an associated HORSES_FEATURED record. I leave it to you for checking your data to decide if it should really be an INNER JOIN. Likewise for the STATES table relationship...

How can I turn a single row column into a scalar in SQL?

This is sort of what I want to do, but MySQL doesn't seem to accept it.
SELECT Name, Content, Lft, Rht FROM Articles WHERE
(Lft > (SELECT Lft FROM Articles WHERE idArticle = 1))
AND WHERE
(Rht < (SELECT Rht FROM Articles WHERE idArticle = 1));
I'm implementing the modified preorder tree transversal algorithm, and I want to get all the children of an Article using a single database query.
The Articles table looks like this:
Articles
+=============+===========+
| Type | Name |
+=============+===========+
| VARCHAR(45) | Name |
+-------------+-----------+
| LONGTEXT | Content |
+-------------+-----------+
| INT | Lft |
+-------------+-----------+
| INT | Rht |
+-------------+-----------+
| INT | idArticle |
+-------------+-----------+
idArticle is a primary key, and there are UNIQUE indexes on the Lft and Rht columns.
How might something like this be accomplished?
*Note: I'm currently using MySQL but I'd like to avoid any MySQL extensions where possible, because there are possible plans to move to another DB like Postgres or Oracle sometime in the future...
It's not being accepted because the WHERE keyword can only appear once in a query (outside of a subquery):
SELECT x.name,
x.content,
x.lft,
x.rht
FROM ARTICLES x
WHERE EXISTS(SELECT NULL
FROM ARTICLES y
WHERE y.idarticle = 1
AND y.lft < x.lft)
AND EXISTS(SELECT NULL
FROM ARTICLES z
WHERE z.idarticle = 1
AND z.rht > x.rht)
Apparently it was just a simple syntax error (too many WHERE), but if you want to avoid the scalar subselect, you could also do a join (with the potential advantage that the row with idArticle 1 only needs to be loaded once, an optimization that your query planner may or may not be able to figure out by itself):
SELECT a.Name, a.Content, a.Lft, a.Rht FROM Articles a
join Articles b on (b.idArticle =1 )
where a.lft > b.lft and a.rht < b.rht;
Alternate equivalent
SELECT a.Name, a.Content, a.Lft, a.Rht
FROM Articles a
join Articles b on a.lft > b.lft
and a.rht < b.rht
AND b.idArticle = 1 ;