MySQL - Interchange column value from one row onto another - mysql

SELECT OlineDate, OlineOrder, OlineDesc, OlineGroup, OlinePrice
FROM tblorderlines
WHERE DATE(OlineDate) = '2019-10-19' AND OlineOrder = 170
AND OlineGroup IN ('spec')
|====================================================================|
| OlineOrder |OlineDate | OlineDesc | OlineGroup | OlinePrice |
|============+============+===========+================+=============|
| 10 | 2019-10-19 | Coupon | spec | -2.42 |
|------------+------------+-----------+----------------|-------------|
| 10 | 2019-10-19 | 10% OFF | spec | 0.00 |
|------------+------------------------+----------------+-------------|
I am looking for a query that would interchange the '10% off' value over the 'Coupon' value. The only results I've found that may produce the result I want are pivot tables but those don't exist in MySQL. Is there another route I can take?

Related

99% working behavior from mysql statement needs to be 100%

I have inherrited a DB that I've been tasked to mine for Data.
There are 2 tables that are loosely associated - atm and dslams.
The atm table contains "remotename", "rst", and "CardNumber" fields that relate to the dslams "hostname" field.
The atm table contains the port information for the dslam cards and the dslams table contains the information about the dslam card itself.
I've been tasked with printing out all the locations (dslams.name) that have a certain type of card (dslams.model="6256") and a count of all the ports on that card that have a certain level of service (atm.speed LIKE "RI_%%09" OR atm.speed LIKE "RI%%1%").
I've crafted the following statement which almost works...
SELECT distinct(dslams.name) AS Remote, Count(atm.speed) AS Customers, dslams.model
FROM dslams
LEFT JOIN atm
ON (dslams.hostname = CONCAT(atm.remotename,'-',atm.rst,'-S',atm.CardNumber)) AND (atm.speed LIKE "RI_%_%09" OR atm.speed LIKE "RI_%_%1_%")
GROUP BY dslams.name
HAVING dslams.model="6256"
ORDER BY dslams.name;
This prints out exactly what I need for all but 1 of the locations.
ie.
MariaDB [dsl]> SELECT distinct(dslams.name) AS Remote, Count(atm.speed) AS Customers, dslams.model
-> FROM dslams
-> LEFT JOIN atm
-> ON (dslams.hostname = CONCAT(atm.remotename,'-',atm.rst,'-S',atm.CardNumber)) AND (atm.speed LIKE "RI_%_%09" OR atm.speed LIKE "RI_%_%1_%")
-> GROUP BY dslams.name
-> HAVING dslams.model="6256"
-> ORDER BY dslams.name;
+---------+-----------+-------+
| Remote | Customers | model |
+---------+-----------+-------+
| ANTH-C2 | 1 | 6256 |
| BETY-C2 | 1 | 6256 |
| BHOT-C2 | 6 | 6256 |
| BNSH-C2 | 1 | 6256 |
| BUG2-C2 | 1 | 6256 |
| CCRK-C2 | 0 | 6256 |
...
| STLN-C2 | 1 | 6256 |
| SUMR-C2 | 2 | 6256 |
...
| WGRV-C2 | 0 | 6256 |
+---------+-----------+-------+
63 rows in set (0.34 sec)
For some reason there's one location that's not getting counted - STWL-C2.
MariaDB [dsl]> SELECT distinct(name), model FROM dslams WHERE model="6256" order by name;
+---------+-------+
| name | model |
+---------+-------+
| ANTH-C2 | 6256 |
| BETY-C2 | 6256 |
| BHOT-C2 | 6256 |
| BNSH-C2 | 6256 |
| BUG2-C2 | 6256 |
| CCRK-C2 | 6256 |
...
| STWL-C2 | 6256 |
...
| WGRV-C2 | 6256 |
+---------+-------+
64 rows in set (0.00 sec)
There's no difference in the tables between the STWL-C2 location and the other locations so it should print out with a count of 0.
Can anyone help me figure out why that 1 location is being missed?
Any help or direction would be appreciated as I am a rookie SQL programmer trying to understand this as best I can.
Best Regards,
Joe
Don't use HAVING dslams.model = '6256', put that in the WHERE clause. When you use HAVING, it filters after grouping. When you group by name, the result can contain the model from any row in the group, and it won't necessarily choose model = '6256'.
SELECT dslams.name AS Remote, Count(atm.speed) AS Customers, dslams.model
FROM dslams
LEFT JOIN atm
ON (dslams.hostname = CONCAT(atm.remotename,'-',atm.rst,'-S',atm.CardNumber)) AND (atm.speed LIKE "RI_%_%09" OR atm.speed LIKE "RI_%_%1_%")
WHERE dslams.model = '6256'
GROUP BY dslams.name
ORDER BY dslams.name;

check if row has a particular value (perl,mysql)

I'm trying to identify if a row has the value '1' anywhere in it (AKA any column). Is there an easy way to do this without searching every column with fetchrow_array? I've included a small table I've been working with as an example.
mysql> select * from Case_Tracking;
+--------------------+---------+---------+----------+---------+----------+---------------+
| accession_number | cyp2d6 | cyp2c19 | factorII | factorV | apoe | vkorc1_cyp2c9 |
+--------------------+---------+---------+----------+---------+----------+---------------+
| AIB14-1116-0000453 | Luminex | Luminex | Hologic | 1 | ABI 7500 | Genmark |
| AIB14-1123-0000074 | NULL | Luminex | Hologic | Hologic | ABI 7500 | Genmark |
+--------------------+---------+---------+----------+---------+----------+---------------+
It would be better to search every column using SQL (WHERE accession_number = '1' OR cyp2d6 = '1' OR ...) since you'd only need to fetch matching results.

Mysql remove duplicate from a row and update the row

I have a mysql table like
+-----------------+---------------------------------------------------------------+---------+
| col_key |member_column | weight |
+-----------------+---------------------------------------------------------------+---------+
| 4:20131205:0922 | 018210020504;4.1672|018210020504;4.1672 | 8.3344 |
| 4:20131204:0923 | 015819070006;13.8584|015819070006;13.8584 | 27.7168 |
| 4:20131202:0922 | 018710040303;8.7864 | 8.7864 |
| 4:20131204:0923 | 017319010003;2.7044|017319010004;2.7044 | 5.4088 |
| 4:20131202:0922 | 055320020104;7.3357 | 7.3357 |
| 4:20131217:0922 | 019120020404;7.8727|019120020404;7.8727 | 15.7454 |
| 4:20131223:0923 | 011820010203;11.5213 | 11.5213 |
| 4:20131216:0925 | 018320010403;13.7416 | 13.7416 |
| 4:20131217:0922 | 017420020205;6.7384 | 6.7384 |
| 4:20131217:0922 | 019723010104;4.3660|050122010004;12.1407|050122010003;12.1407 | 28.6474 |
| 4:20131224:0926 | 022923040107;10.2461|022923040106;10.2461 | 20.4922 |
| 4:20131216:0925 | 050122010004;12.1407|050122010003;12.1407 | 24.2814 |
| 4:20131216:0925 | 061020030007;3.8048 | 3.8048 |
+-----------------+---------------------------------------------------------------+---------+
Here member_columns has values different member:weight which is | separated. Weight columns has total weight for the member in a particular row.
We need to remove duplicate members from the member_columns and update the weight correspondingly.
Example:
row with col_key 4:20131205:0922 has member_column in which members are repeated .
I need this columns updated to
4:20131205:0922 | 018210020504;4.1672 | 4.1672
Similarly for the column
4:20131217:0922 | 019723010104;4.3660|050122010004;12.1407|050122010003;12.1407|28.6474
I need it to be updated as
4:20131217:0922 | 019723010104;4.3660|050122010004;12.1407|16.5067
I was looking towards cursor for the solution but learn that cursor do not update the actual data.
Please HELP .
For this approach, you will need to take help from any server side script. So the Process to follow would be
1) select all rows having member_column as your resultset field from the table narrowing down by any condition of your choice
2) Iterate the result set
3) Explode the member_column field by "|" and form an array of strings. which would come as
array("4:20131217:0922", "019723010104;4.3660","050122010004;12.1407","16.5067");
4) Do all your computation and remove duplicates
5) once you have a unique array, implode it back with dash "|"
6) update the row back.
Hope it helps :)

MySQL: optimize query for scoring calculation

I have a data table that I use to do some calculations. The resulting data set after calculations looks like:
+------------+-----------+------+----------+
| id_process | id_region | type | result |
+------------+-----------+------+----------+
| 1 | 4 | 1 | 65.2174 |
| 1 | 5 | 1 | 78.7419 |
| 1 | 6 | 1 | 95.2308 |
| 1 | 4 | 1 | 25.0000 |
| 1 | 7 | 1 | 100.0000 |
+------------+-----------+------+----------+
By other hand I have other table that contains a set of ranges that are used to classify the calculations results. The range tables looks like:
+----------+--------------+---------+
| id_level | start | end | status |
+----------+--------------+---------+
| 1 | 0 | 75 | Danger |
| 2 | 76 | 90 | Alert |
| 3 | 91 | 100 | Good |
+----------+--------------+---------+
I need to do a query that add the corresponding 'status' column to each value when do calculations. Currently, I can do that adding the following field to calculation query:
select
...,
...,
[math formula] as result,
(select status
from ranges r
where result between r.start and r.end) status
from ...
where ...
It works ok. But when I have a lot of rows (more than 200K), calculation query become slow.
My question is: there is some way to find that 'status' value without do that subquery?
Some one have worked on something similar before?
Thanks
Yes, you are looking for a subquery and join:
select s.*, r.status
from (select s.*
from <your query here>
) s left outer join
ranges r
on s.result between r.start and r.end
Explicit joins often optimize better than nested select. In this case, though, the ranges table seems pretty small, so this may not be the performance issue.

Table has pairs of matching records, need to select and update only one record

I have a table with pairs of matching records that I query like this:
select id,name,amount,type from accounting_entries
where name like "%05" and amount != 0 order by name limit 10;
Results:
+------+----------------------+--------+-------+
| id | name | amount | type |
+------+----------------------+--------+-------+
| 786 | D-1194-838HELLUJP-05 | -5800 | DEBIT |
| 785 | D-1194-838HELLUJP-05 | -5800 | DEBIT |
| 5060 | D-1195-UOK4HS5POF-05 | -5000 | DEBIT |
| 5059 | D-1195-UOK4HS5POF-05 | -5000 | DEBIT |
| 246 | D-1196-0FUCJI66BX-05 | -7000 | DEBIT |
| 245 | D-1196-0FUCJI66BX-05 | -7000 | DEBIT |
| 9720 | D-1197-W2J0EC1BOB-05 | -6500 | DEBIT |
| 9719 | D-1197-W2J0EC1BOB-05 | -6500 | DEBIT |
| 2694 | D-1198-MFKIKHGW0S-05 | -5500 | DEBIT |
| 2693 | D-1198-MFKIKHGW0S-05 | -5500 | DEBIT |
+------+----------------------+--------+-------+
10 rows in set (0.01 sec)
I need to perform an update so that the resulting data will look like this:
+------+----------------------+--------+--------+
| id | name | amount | type |
+------+----------------------+--------+--------+
| 786 | D-1194-838HELLUJP-05 | -5800 | DEBIT |
| 785 | C-1194-838HELLUJP-05 | 5800 | CREDIT |
| 5060 | D-1195-UOK4HS5POF-05 | -5000 | DEBIT |
| 5059 | C-1195-UOK4HS5POF-05 | 5000 | CREDIT |
| 246 | D-1196-0FUCJI66BX-05 | -7000 | DEBIT |
| 245 | C-1196-0FUCJI66BX-05 | 7000 | CREDIT |
| 9720 | D-1197-W2J0EC1BOB-05 | -6500 | DEBIT |
| 9719 | C-1197-W2J0EC1BOB-05 | 6500 | CREDIT |
| 2694 | D-1198-MFKIKHGW0S-05 | -5500 | DEBIT |
| 2693 | C-1198-MFKIKHGW0S-05 | 5500 | CREDIT |
+------+----------------------+--------+--------+
10 rows in set (0.01 sec)
One entry should negate the other entry. It doesn't matter if I update the first or second matching record, what matters is that one has a positive amount and the other has a negative amount. And the type and name need to be updated.
Any clues on how to do this? What would the update command look like? Maybe using a group by clause? I have some ideas on how to do it with a stored procedure, but can I do it with a simple update?
Try this:
UPDATE accounting_entries as ae
SET name = 'C' + SubString(name, 1, Length(name) - 1))
amount = amount * -1
type = 'Credit'
WHERE id =
(SELECT MIN(id) FROM
(SELECT * FROM accounting_entries) as temp
GROUP BY name)
The key is the subquery in the WHERE section that limits the updates to the lowest ID of each name value. The assumption is that the lower ID is the one that you will always want to update. If this is not correct, then update the subquery based on whatever rule you would use.
Edit: Update to subquery based on technique found here, due to limitation on mysql defined here.
This query gives a method for updating all records at once (as it seemed like this is what the OP was looking for. However, the most efficient way to do this would be to enumerate through all records in code (php, asp.net, etc), and through code-based methods update the rows that needed to change. This would eliminate the performance issues inherent with running updates off of subqueries in mysql.
If the ID:s for a pair always match the formula x and x+1, you could say something like
WHERE MOD(`id`, 2) = 1
EDIT: I haven't tested this code, so I can't guarantee that it's possible to put a column name into a MOD like this, but it might be worth a try, and/or further investigation.
Does this constraint hold true all the time (D == -C) ?
If so, you do not need to keep redundant data in your table, store only one "amount" value (for example the debit):
786 | 1194-838HELLUJP-05 | -5800
and then, on the application level, append a D- to the name and get the raw amount or append a C- and get the - amount.