Use LIKE with multiple names from a different table in UPDATE - sql

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

Related

KQL :: return only tags with more than 4 records

I have created a Kusto query that allows me to return all our database park. The query only takes 10 lines of code:
Resources
| join kind=inner (
resourcecontainers
| where type == 'microsoft.resources/subscriptions'
| project subscriptionId, subscriptionName = name)
on subscriptionId
| where subscriptionName in~ ('Subscription1','Subscription2')
| where type =~ 'microsoft.sql/servers/databases'
| where name != 'master'
| project subscriptionName, resourceGroup, name, type, location,sku.tier, properties.requestedServiceObjectiveName, tags.customerCode
By contract we are supposed to give only 4 Azure SQL Database per customer but sometimes developers take a copy of them and they rename it _old or _backup and suddenly a customer can have 5 or 6 databases.
This increase the overall costs of the Cloud and I would like to have a list of all customers that have more than 4 databases.
In order to do so I can use the tag tags.customerCode which has the 3 letters identifier for each customer.
The code should work like this: if a customer is called ABC and there are 4 Azure SQL Databases with tags.customerCode ABC the query should return nothing. If there are 5 or 6 databases with tags.customerCode ABC the query should return all of them.
Not sure if Kusto can be that flexible.
Here is a possible solution.
It should be noted that Azure resource graph supports only a limited subset of KQL.
resourcecontainers
| where type == 'microsoft.resources/subscriptions'
//and name in~ ('Subscription1','Subscription2')
| project subscriptionId, subscriptionName = name
| join kind=inner
(
resources
| where type =~ 'microsoft.sql/servers/databases'
and name != 'master'
)
on subscriptionId
| project subscriptionId, subscriptionName, resourceGroup, name, type, location
,tier = sku.tier
,requestedServiceObjectiveName = properties.requestedServiceObjectiveName
,customerCode = tostring(tags.customerCode)
| summarize dbs = count(), details = make_list(pack_all()) by customerCode
| where dbs > 4
| mv-expand with_itemindex=db_seq ['details']
| project customerCode
,dbs
,db_seq = db_seq + 1
,subscriptionId = details.subscriptionId
,subscriptionName = details.subscriptionName
,resourceGroup = details.resourceGroup
,name = details.name
,type = details.type
,location = details.location
,tier = details.tier
,requestedServiceObjectiveName = details.requestedServiceObjectiveName

SQL join on returns none values

// 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

Query with conditions on multiple value column

I am building report in Oracle Apex 4.2. Table that report is build on has multiple values inside one of the columns.
-----------------------------------
| ID | NAME | PROJECT_ID |
-----------------------------------
| 1 | P1 | 23:45:56 |
| 2 | P2 | 23 |
| 3 | P3 | 45:65 |
-----------------------------------
I would like to build a query to retrieve names based on project_id's.
Select name from table where project_id = 23;
This obviously will return P2 only however I would like to build a query which would return P1 and P2 if we searched for 23.
Any help greatly appreciated.
You can use LIKE instead of = :
Select name from table where project_id LIKE '%23%';
If you've got a common delimiter such as the ':' in your example you could use the following to exclude results like '123':
SELECT name FROM table WHERE ':' || project_id || ':' LIKE '%:23:%'
By concatenating the delimiter to the front and back of the string, you don't have to write multiple criteria: LIKE '23:%' OR LIKE '%:23:%' OR LIKE '%:23' to handle the first and last number in the list.
This is a common design in Apex due to its builtin support for colon-delimited strings (e.g. to drive shuttle controls and other item types).
I generally use this pattern:
Select name from table where INSTR(':'||project_id||':',':23:') > 0;
P.S. It's a pity about that column name - I would have called it something like PROJECT_ID_LIST.

Universal SQL query for different input elements

I have a SQL query problem with the following abstract sample context: There are 2 different input data for my sql query defined as ''MainElement'' with key 123 for the one and 789 for the other main element.
Further I have a table called Relation with columns pk, FirstElement, SecondElement and ThirdElement.
Furthermore there is a table called Props with the columns pk, name and valueString. The special feature about this context is that column name in Props defines 2 further columns called 4thElement and 5thElementof table Relation as a row with its values in column valueString .
|pk | 1stElement | 2ndElement | 3rdElement |
|abc|-----123----|-----456----|-----null---|
|def|-----789----|-----101112-|---131415---|
|Pk | Name | ValueString |
|def|4thElement|161718---|
|def|5thElement|ghi------|
As you can see the MainElement 789 has a value for 4thElement and 5thElement in Props, but MainElement 123 hasn't any value in Props.
What I need is an universal SQL query with input value 1stElement e.g., 123 or 789 that returns me a result for both main elements independent of the fact that MainElement 123 hasn't any value in Props.
Sample result:
|1stElement | 2ndElement | 3rdElement | 4thElement | 5thElement |
|123--------|------456---|-----null---|---null-----|----null----|
|789--------|----101112--|---131415---|---161718---|----ghi-----|
I am using Oracle SQL Developer.
Select
rel.1stElement,
....
From
Relation rel,
Props pro,
Where
?
Thanks in advance.
This should do the work, this is typically a pivot query that you need:
SELECT rel.pk, rel.1stElement, rel.2ndElement, rel.3rdElement
, MAX(CASE WHEN pro.Name = '4thElement'
THEN pro.ValueString
ELSE NULL
END) as 4thElement
, MAX(CASE WHEN pro.Name = '5thElement'
THEN pro.ValueString
ELSE NULL
END) as 5thElement
FROM Relation rel
LEFT OUTER JOIN Props pro
ON rel.pk = pro.pk
GROUP BY rel.pk, rel.1stElement, rel.2ndElement, rel.3rdElement

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...