How to use Substring_Index in update statement in MYSQL - mysql

Using Mysql Sql, How do I update an a table where the field values in "ON" clause
dont match. The order in old table has a few extra letters. The code runs, but the
quantity does not update. Maybe I could concatenate order??
UPDATE t.filled n JOIN t.open o ON n.item = o.item AND n.order = o.order
SET o.Quantity = o.Quantity + n.Quantity WHERE (SUBSTRING_INDEX(n.order,":",-1) = "CLD" )

Solution was to concat one of the x.order to match the other, thus dropping the
where clause.

Related

How to use variables column name in where clause MySQL?

In this query:
SELECT *
FROM general_settings AS general_settings
JOIN settings_attribute AS settings_attribute ON settings_attribute.id = general_settings.settings_attribute_id
JOIN user_settings AS user_settings ON general_settings.user_settings_id = user_settings.id
WHERE
(settings_attribute.name = 'AAA' AND brand_settings.AAA <> general_settings.value)
OR
(settings_attribute.name = 'BBB' AND brand_settings.BBB <> general_settings.value)
OR
(settings_attribute.name = 'CCC' AND brand_settings.CCC <> general_settings.value)
;
I want a way using MySQL or Redshift to use settings_attribute.name as column name to avoid writing all the attribute names as a static in the query,
for example like this:
SELECT *
FROM general_settings AS general_settings
JOIN settings_attribute AS settings_attribute ON settings_attribute.id = general_settings.settings_attribute_id
JOIN user_settings AS user_settings ON general_settings.user_settings_id = user_settings.id
WHERE
brand_settings.#settings_attribute.name <> general_settings.value
;
No, this is not possible. In SQL, all identifiers (e.g. column names) must be explicit and fixed in the query at the time it is parsed, so the SQL engine can verify that the columns actually exist before it begins executing. It's not possible for a query to name different columns based on the string values it reads during execution.
What would happen if your settings_attribute.name contained 'XYZ' in some row, but there was no column by that name? It would be an error if you named a column that didn't exist, but in SQL that is checked at the time the query is parsed.

How to update columns in another table from a select query?

i want to update some columns in another table from a query result. I keep getting error. Please help.
Update customer_info
set customer_info.reader_ID = aisle_info.reader_ID,
customer_info.tag_no = tag_logs.tag_no,
customer_info.area = aisle_info.area,
customer_info.max_timestamp = TIMESTAMPDIFF(SECOND,MIN(tag_logs.timestamp),MAX(tag_logs.timestamp))
FROM tag_logs
INNER join aisle_info ON tag_logs.reader_ID = aisle_info.reader_ID
WHERE T.tag_no = 515988190124;
1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'FROM tag_logs
INNER join aisle_info ON tag_logs.reader_ID = aisle_info.reader_I' at line 5
You were close. Different databases have slightly different syntax on updates from select/join. Think of MySQL as a select statement, and use the alias of the primary table you are trying to update and then the SET clauses are after that.
So I first will start by writing the SELECT query by itself.
select
CI.Tag_No,
AI.Reader_ID,
AI.Area,
MIN( TL.TimeStamp ) MinTime,
MAX( TL.TimeStamp ) MaxTime
from
customer_info CI
join tag_logs TL
CI.tag_no = TL.tag_no
join aisle_info AI
on TL.Reader_ID = Reader_ID
WHERE
CI.tag_no = 515988190124
group by
CI.Tag_No,
AI.Reader_ID,
AI.Area
So this gives us the final results of what you want, and you can confirm it as needed.
Then apply your update such as
update Customer_Info CIUpd
JOIN
( select
CI.Tag_No,
AI.Reader_ID,
AI.Area,
MIN( TL.TimeStamp ) MinTime,
MAX( TL.TimeStamp ) MaxTime
from
customer_info CI
join tag_logs TL
CI.tag_no = TL.tag_no
join aisle_info AI
on TL.Reader_ID = Reader_ID
WHERE
-- notice your filter is HERE for the one tag_no you want to update
-- and will result with only this on TAG_NO set of values returned
CI.tag_no = 515988190124
group by
CI.Tag_No,
AI.Reader_ID,
AI.Area ) FirstQuery
-- the JOIN will ensure updating only on that one tag_no
ON CIUpd.Tag_No = FirstQuery.Tag_No
set
CIUpd.Reader_ID = FirstQuery.Reader_ID,
CIUpd.Area = FirstQuery.Area,
CIUpd.Max_TimeStamp = TimeStampDiff( second, FirstQuery.MinTime, FirstQuery.MaxTime )
Now this is not a perfect answer as your original query was not a proper query using the MIN() / MAX() context. When doing an aggregate query, you need to apply a group by on all NON aggregate columns. In this case you did not clarify any such group consideration on the Reader_ID and Area which COULD result in multiple rows from your tag_logs and aisle_info tables.
If the aisle info will be the same all the time for a given Tag_No, then that's simple, just skip the grouping on that and change those column retrieve values as MAX() each. if they never change, MAX() or even MIN() will always return the same value and not have an issue with the aggregate query without non-aggregate columns.
If you can provide additional clarification of data, purpose, etc, please edit your original post vs just leaving a comment. Then leave a comment for me to please review with updated info.

USING IF with UPDATE MYSQL

Im trying to do an update with a IF function
IF(SELECT 'FUNCION' FROM tickets
WHERE (FUNCION = COR) AND (tickets.CLIENTE=clientes.CLIENTE))
THEN UPDATE `clientes` SET `ESTADO` = 'I';
I tried this but it seems I have a syntax error.
How can I get this to work?
EDIT: I want to update 'ESTADO' to 'I' if 'FUNCION', from another table, is 'COR' and the fields 'CLIENTE' match each other.
You can use a join operation in an UPDATE statement.
It's not clear to me what COR is a reference to, so I'm going to assume it's supposed to be a string literal, not a reference to a column name.
Here's an example:
UPDATE clientes c
JOIN tickets t
ON t.cliente = c.cliente
AND t.funcion = 'COR'
SET c.estado = 'I'
That says, find all rows in clientes that have a "matching" row in tickets, and set the estado column to 'I' on those rows.
Think about it this way... write a SELECT query first to identify the rows you want to update, and filter out the ones you don't.
SELECT c.* -- please don't use * in code in applications!
, t.funcion
FROM clientes c
JOIN tickets t
ON t.cliente = c.cliente
AND t.funcion = 'COR'
--or--
SELECT c.*
FROM clientes c
WHERE EXISTS ( SELECT 1
FROM tickets t
WHERE t.cliente = c.cliente
AND t.funcion = 'COR'
)
Once you have a SELECT statement working (that retrieves ONLY the rows you want to update), you can convert that into an UPDATE, by replacing SELECT ... FROM with the keyword UPDATE, and add a SET clause before the WHERE clause.
There's also some "tricks" we can play in the expression in the SET, to do some conditional assignment. To leave the column unchanged, assign the current value back to the column.
For example, to replace only NULL values of estado
SET c.estado = IF(c.estado IS NULL,'I',c.estado)
If the boolean expression (first argument in the IF() function) evaluates to TRUE, then return the result of the evaluation of the second argument (in this example 'I'), otherwise, return the current value of the estado column.
That's not how you write a conditional update. Use a where clause:
UPDATE clientes
SET estado='I'
WHERE (funcion = cor) AND (tickets.client=clients.cliente)
This won't work, since you're referring to fields/tables that aren't joined into the query.

01427. 00000 - "single-row subquery returns more than one row"

I'm getting 01427. 00000 - "single-row subquery returns more than one row" error while executing below procedure. the issue , what i believe , is in subquery
SELECT paymentterm FROM temp_pay_term WHERE pid = d.xProject_id
but how can i get rid of it.Now, i have added the complete code. please check and let me know the wrong tell me if more info. is to be provided.
CREATE OR REPLACE PROCEDURE paytermupdate IS
recordcount INT;
vardid NUMBER(38);
varpaymentterm VARCHAR2(200 CHAR);
BEGIN
recordcount := 0;
SELECT COUNT(1) INTO recordcount
FROM temp_pay_term;
IF recordcount > 0 THEN
FOR x IN (SELECT DISTINCT r.ddocname
FROM temp_pay_term p, docmeta d, revisions r
WHERE TO_CHAR(p.pid) = d.xproject_id AND r.did = d.did )
LOOP
SELECT MAX(did) INTO vardid
FROM revisions r
WHERE r.ddocname = x.ddocname
GROUP BY r.ddocname;
UPDATE docmeta d
SET paymentterm = (
SELECT paymentterm
FROM temp_pay_term
WHERE pid = d.xproject_id
)
WHERE d.did = vardid;
INSERT INTO documenthistory (dactionmillis, dactiondate, did, drevclassid,
duser, ddocname, daction, dsecuritygroup, paymentterm)
SELECT
to_number(TO_CHAR(systimestamp, 'FF')) AS dactionmillis,
TRUNC(systimestamp, 'dd') AS dactiondate,
did,
drevclassid,
'sysadmin' AS duser,
ddocname,
'Update' AS daction,
dsecuritygroup,
paymentterm
FROM revisions
WHERE did = vardid;
END LOOP;
COMMIT;
END IF;
END paytermupdate;
Do you use something like
select x,y,z, (subquery) from ?
If you are getting ORA-01427 you should think how to make filter conditions in your subquery more restrictive, and these restrictions should be business reasonable, not just simply "and rownum <=1".
As you want to update a record through that sub query you should put more filter conditions in it. You can decide on the filter conditions on the basis of the value you want to update in the table in outer query. If there are more values which satisfy the condition (which I do not believe is ideal but just in case) then rownum <=1 would suffice.
Two basic options come to mind. I'll start with the simplest.
First, add distinct to the subquery.
SET paymentterm =
(SELECT distinct paymentterm
FROM temp_pay_term
WHERE pid = d.xProject_id
)
Second, if you're receiving multiple distinct values from the subquery, then you will either have to (a) rework your script to not use a subquery or (b) limit values returned (as #Baljeet suggested) using more filter criteria or (c) pick which of the multiple distinct values you want using an aggregate function.
Using the aggregate method, I'm guessing PaymentTerm is a number of months or years? Even if it's a n/varchar field (i.e., "6 months"), you can still use the MIN() and MAX() aggregates (or at least you can in t-sql). If it's a numeric field, you could also use average. You'll have to figure out which works best for your business needs.

Mysql, combining and querying results with sub queries or temp tables

I am running into some trouble with the following circumstances:
I have a query that creates two temp tables, and the following select to join them together--
SELECT * FROM result
INNER JOIN result2 ON result2.packetDetailsId = result.packetDetailsId
I am then trying to create another column from concatenating a few of the resulting fields and then use that to reference/query against another table. Is there a way to accomplish this in one query? Should I get away from the temp tables?
Thank you again in advance.
update: If I try to alias the combination of the two temp tables I get an error message stating [Err] 1060 - Duplicate column name 'packetDetailsId'
select * from (
SELECT * FROM result
INNER JOIN result2 ON result2.packetDetailsId = result.packetDetailsId) as myalias
Another Update: I almost have it working as one query but I get the result "(BLOB)" in the column I concoctenated:
select packet_details.packetDetailsId,products.productId,Credit,AccountNum,OrderStat, CONCAT(products.productId,Credit,'_',OrderStat) as consol from (
select packetDetailsId, GROUP_CONCAT(Credit) AS Credit, GROUP_CONCAT(AccountNum) AS AccountNum, GROUP_CONCAT(OrderStat) AS OrderStat FROM
( SELECT pd_extrafields.packetDetailsId,
CASE WHEN pd_extrafields.ex_title LIKE ('%Credit%')
THEN pd_extrafields.ex_value ELSE NULL END as Credit,
CASE WHEN pd_extrafields.ex_title LIKE ('%Account%')
THEN pd_extrafields.ex_value ELSE NULL END as AccountNum,
CASE WHEN pd_extrafields.ex_title LIKE ('%Existing%')
THEN pd_extrafields.ex_value ELSE NULL END as OrderStat
FROM pd_extrafields )AS TempTab GROUP BY packetDetailsId ) as alias2
INNER JOIN packet_details ON alias2.packetDetailsId = packet_details.packetDetailsId
INNER JOIN sales ON packet_details.packetDetailsId = sales.packetDetailsId
INNER JOIN sold_products ON sales.saleId = sold_products.saleId
INNER JOIN products ON sold_products.productId = products.productId
If I understand correctly, you already have the temporary tables created and you need to "concatenate" the results, using from ... inner join ...
The only possible restriction you may have is that you can only reference your temporary tables once in your from clause; besides that, there are no other restrictions (I frequently use temporary tables as intermediate steps in the creation of my final result).
Tips
Let's say your temp tables are temp_result1 and temp_result2. Both tables have a field packedDetailsId, on which the join will be performed. Remember to create the appropriate indexes on each table; at the very least you need to index packedDetailsId on both tables:
alter table temp_result1
add index PDI(packedDetailsId);
alter table temp_result2
add index PDI(packedDetailsId);
Now, just execute a query with the desired join and concatenation. If concat returns BLOB, then cast the result as char (of course, I'm assuming you need a text string):
select r1.*, r2.*, cast(concat(r1.field1, ',', r2.field2) as char) as data_concat
from temp_result1 as r1
inner join temp_result2 as r2 on r1.packedDetailsId = r2.packedDetailsId;
I see your problem is that GROUP_CONCAT is returning BLOB values... It's normal (MySQL doesn't know a priori how to return the values, so it returns binary data); just use the cast function.
Hope this helps you
so, if the result2 and result are both temp tables, you will have to include the # if local temp table and ## if global temp table
so your statements should be :
SELECT * FROM #result
INNER JOIN #result2 ON #result2.packetDetailsId = #result.packetDetailsId
My Bad. This is only applicable for MS SQL