MySQL divide rows an show result on new row - php

I am having difficulties with an MySQL query.
The database looks like this:
Name Unit Int
---------------------
A1 Kilo 20
A1 Price 5
A2 Kilo 15
A2 Price 3
Here is what I'm trying to do:
| Name | Unit | int |
| A1 | Kilo | 20 |
| A1 | Price | 5 |
| A1 | K/P | 4 |
| A2 | Kilo | 15 |
| A2 | Price | 3 |
| A2 | K/P | 5 |
As you can see, I want to insert a new row for every A1 and A2 with a result of Kilo divided by Price.
Is this even possible to do?
If so, could anyone point me in the right direction? I am pretty lost here, and have tried to sweep the internet the last many days, whitout result. I have tried far more ideas than I wish to bore you with.

You could do something like this in your SELECT to calculate it on-the-fly with the latest available data (thus preventing hard-storing something that could later become outdated if the Price/Kilo were to change):
SELECT `kilo`.`name`, (`kilo`.`int` / `price`.`int`) AS 'K/P' FROM `stuff` AS `kilo`
LEFT JOIN `stuff` AS `price` ON (`kilo`.`name` = `price`.`name`)
WHERE `kilo`.`unit`='Kilo' AND `price`.`unit`='Price';
This would return:
+------------+
| name | K/P |
|------------|
| A1 | 4 |
| A2 | 5 |
+------------+
And if you'd really want to insert it into your database you could INSERT ... SELECT the above. Like so:
INSERT INTO `stuff` (`name`, `unit`, `int`)
SELECT `kilo`.`name`, 'K/P', (`kilo`.`int` / `price`.`int`) FROM `stuff` AS `kilo`
LEFT JOIN `stuff` AS `price` ON (`kilo`.`name` = `price`.`name`)
WHERE `kilo`.`unit`='Kilo' AND `price`.`unit`='Price';
See the full SQL Fiddle example here.

You can get all results with
SELECT * FROM (
(SELECT * FROM your_table_name)
UNION
(SELECT r1.Name as Name, 'K/P', r1.Int/r2.Int
FROM your_table_name r1, your_table_name r2
WHERE r1.Name=r2.Name AND r1.Unit='Kilo' AND r2.Unit='Price'
)
) AS derived_table
ORDER BY Name, FIELD(Unit,'Kilo','Price','K/P');

Related

Make conditional relation on mysql tables using Laravel or PHP

I have tables like below.
Table A
id | val_a
1 | a1
2 | a2
3 | a3
Table B
id | id_a| val_b | resource_type
1 | 2 | b1 | 1
2 | 2 | b2 | 2
3 | 3 | b3 | 3
4 | 3 | b4 | 3
Table Resource_A
id |r_val| id_b
1 | ra1 | 1
Table Resource_B
id |r_val| id_b
1 | rb1 | 2
Table Resource_C
id |r_val| id_b
1 | rc1 | 3
2 | rc2 | 4
If resource_type is 1 in Table B, then table B make relation with table Resource_A.
If resource_type is 2 in Table B, then table B make relation with table Resource_B.
If resource_type is 3 in Table B, then table B make relation with table Resource_C.
Required Output is:
id_b | id_a| val_b |val_a | resource_type| r_val
1 | 2 | b1 | a1 | 1 | ra1
2 | 2 | b2 | a2 | 2 | rb1
3 | 3 | b3 | a3 | 3 | rc1
4 | 3 | b4 | a3 | 3 | rc2
But what is the best way to get it without using loop in laravel?
How Can I achieve this by using Laravel 5.2 OR Laravel 4 OR PHP OR MYSQL Query?
Thanks Ahead.
You only need to join the tables together as I have done below. The tricky part here is bringing in the correct r_val from the three resource tables. We can do this by left joining to each resource table, and then using the following expression to grab the matching value:
COALESCE(t1.r_val, t2.r_val, t3.r_val) AS r_val
This will take the first non NULL value from a resource table, in order of left to right. Assuming that each ID from tableb only appears once, in one of the resource tables, the order of the terms inside COALESCE() should not matter.
SELECT tb.id AS id_b,
tb.id_a,
tb.val_b,
COALESCE(ta.val_a, 'NA') AS val_a,
tb.resource_type,
COALESCE(t1.r_val, t2.r_val, t3.r_val) AS r_val
FROM tableb tb
LEFT JOIN tablea ta
ON tb.id_a = ta.id
LEFT JOIN resource_a t1
ON tb.id = t1.id_b
LEFT JOIN resource_b t2
ON tb.id = t2.id_b
LEFT JOIN resource_c t3
ON tb.id = t3.id_b
Demo here:
SQLFiddle

mysql select distinct while ignoring one column

I have the following problem: I have a table import_data
The table is enriched something like this
| id | profile_id | sku | vendor | price | importRun |
| 1 | 39 | 123 | myVen | 2.0 | 1 |
| 2 | 39 | 456 | myVen | 2.0 | 1 |
| 3 | 39 | 123 | myVen | 3.0 | 2 |
What I need to get is an output of all elements, but only once. Every sku must be unique. To make it even worse, I need the newest data, if they are redundant.
My output should be like this:
| id | profile_id | sku | vendor | price | importRun |
| 2 | 39 | 456 | myVen | 2.0 | 1 |
| 3 | 39 | 123 | myVen | 3.0 | 2 |
Short Summary about the structure:
ID = PK
sku = a unique identifier for an article
importRun = Needed for comparision.
So, to explain it: I have an import-script, which reads a given CSV-file and imports all articles listed in it. I get this CSV-file in a regular period (once a week). I need to collect all data and save it, to create a price-evolution later on.
After every Import, I increment the number of importRun, so that no information is lost (remember, I can't use REPLACE INTO or INSERT IGNORE.
Now, when I export it, I need the newest Data, if a SKU occures multiple times. In this case, the SKU 123 is inserted 2 times on 2 different runs. That means, since my newest Run had the number 2, I need this tupel (and ignore the first one).
When I work with DISINCT, it would still output the same table, since they aren't distinct at all, because importRun differs.
I should be able to use GROUP BY, but I couldn't figure out which value will be taken, the first- or the last one? (importRun 1 or 2)
Update 1
Followed by the idea of #mitkosoft, I tried the following:
SELECT DISTINCT t1.*
FROM import_data t1
INNER JOIN import_profiles imp on t1.profile_id = imp.id
INNER JOIN (
SELECT DISTINCT sku, MAX(importRun) AS importRun
FROM import_data
GROUP BY sku ) t2
ON t1.sku = t2.sku
WHERE imp.creditornr = 73329
AND t1.vendor = 'rackmountit'
AND t1.importRun = t2.importRun
** Update 2 **
I added the complete Structures for all tables, which are relevant.
Import-Data:
|
Import-Profiles
But i still get duplicates :/
All you need to do is to determine MAX(importRun) for each sku:
SELECT
t1.*
FROM
import_data t1
INNER JOIN (
SELECT sku, MAX(importRun) AS importRun FROM import_data GROUP BY sku
) t2
ON t1.sku = t2.sku
AND t1.importRun = t2.importRun
Output is:
+----+------------+-----+--------+-------+-----------+
| id | profile_id | sku | vendor | price | importRun |
+----+------------+-----+--------+-------+-----------+
| 2 | 39 | 456 | myVen | 2.0 | 1 |
| 3 | 39 | 123 | myVen | 3.0 | 2 |
+----+------------+-----+--------+-------+-----------+
2 rows in set
Perhaps you could join on the same table where sku = sku

MySQL struggling with a query to find similar details among products

I have a query to write and I am absolutely stumped on how to do it. Here's my situation, I am trying to provide a particular product_ID, then match all of the other product_IDs in the database that have at least the same intDescription_detail_IDs as the provided product_ID.
The relevant tables look like this:
tblproducts
=========================
product_ID | product_name
=========================
| 1 | dresser |
| 2 | bookcase |
| 3 | table |
| 4 | chair |
=========================
tbldescriptions
=========================================================================
|description_ID| intDescription_product_ID | intDescription_detail_ID |
=========================================================================
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 4 | 2 | 1 |
| 5 | 2 | 2 |
| 6 | 2 | 6 |
| 7 | 3 | 1 |
| 8 | 3 | 3 |
| 9 | 3 | 4 |
| 10 | 4 | 1 |
| 11 | 4 | 2 |
| 12 | 4 | 7 |
As an example, if I provided the product_ID "1", then I would like to return all of the product_IDs that at least have intDescription_detail_ID 1 and 2.
So, the product_IDs that should be returned are 1, 2, and 4, because all of these products have the intDescription_detail_ID of 1 and 2 among their details.
I am highly confused about how to write a query like this, so any help is greatly appreciated!
I should warn you by saying that I may have made a silly mistake here...
DROP TABLE IF EXISTS products;
CREATE TABLE products(product_ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY,product_name VARCHAR(20) NOT NULL UNIQUE);
INSERT INTO products VALUES
(1,'dresser'),
(2,'bookcase'),
(3,'table'),
(4,'chair');
DROP TABLE IF EXISTS product_detail;
CREATE TABLE product_detail
(product_id INT NOT NULL
,detail_id INT NOT NULL
,PRIMARY KEY(product_id,detail_id)
);
INSERT INTO product_detail VALUES
(1,1),
(1,2),
(2,1),
(2,2),
(2,6),
(3,1),
(3,3),
(3,4),
(4,1),
(4,2),
(4,7);
SELECT DISTINCT c.product_id
FROM product_detail a
JOIN product_detail b
ON b.product_id = a.product_id
AND b.detail_id <> a.detail_id
JOIN product_detail c
ON c.product_id <> a.product_id
AND c.detail_id = a.detail_id
JOIN product_detail d
ON d.product_id = c.product_id
AND d.detail_id = b.detail_id
WHERE a.product_id = 1;
+------------+
| product_id |
+------------+
| 2 |
| 4 |
+------------+
Alternative to #Strawberry’s suggestion with JOINs this can also be done using HAVING for filtering products that have (at least) the same number of rows with the same intDescription_detail_IDs as the product the search is done for:
SELECT intDescription_product_ID
FROM tbldescriptions t1
WHERE intDescription_detail_ID IN (
SELECT intDescription_detail_ID
FROM tbldescriptions t2
WHERE t2.intDescription_product_ID = 1
)
GROUP BY intDescription_product_ID
HAVING count(*) >= (
SELECT count(intDescription_detail_ID)
FROM tbldescriptions t3
WHERE t3.intDescription_product_ID = 1
)
http://sqlfiddle.com/#!2/ce698/2
One should keep in mind though that HAVING is applied last, so that will select all products with at least one matching intDescription_detail_ID first, and filter the results based on the actual count afterwards – so depending on the size and characteristic of your data set that might not be the best performing solution.

Select column values as column headers in SQL?

I have a table like this:
------------------------------------------------------
ID | Date | ClientName | TransactionAmount |
------------------------------------------------------
1 | 6/16/13 | C1 | 15 |
------------------------------------------------------
2 | 6/16/13 | C1 | 10 |
------------------------------------------------------
3 | 6/16/13 | C2 | 10 |
------------------------------------------------------
4 | 6/17/13 | C2 | 20 |
------------------------------------------------------
And I would like to get something like this:
------------------------------------------------------------------------
Date | C1_Total_Amount_Transacted | C2_Total_Amount_Transacted |
------------------------------------------------------------------------
6/16/13 | 25 | 10 |
------------------------------------------------------------------------
6/17/13 | 0 | 20 |
In the second table Date is unique also I there are x clients in the databse the
resul table will have x + 1 columns (1 fore date and x one for each client).
There might be necessary to write some PHP code and more querys, any working solution
is perfect, I don`t need a full SQL solution.
Thanks
I presume that you are rather new to SQL. This type of query requires conditional summation. And it is quite easy to express in SQL:
select `date`,
sum(case when Client_Name = 'C1' then TransactionAmount else 0 end) as C1,
sum(case when Client_Name = 'C2' then TransactionAmount else 0 end) as C2
from t
group by `date`
But, you have to list each client in the query. You always have to specify the exact column headers for a SQL query. If you don't know them, then you need to create the SQL as a string and then execute it separately. This is a rather cumbersome process.
You can often get around that by using group_concat(). This puts the values in a single column, with a separator of your choice (default is a comma):
select `date`, group_concat(amount)
from (select `date`, ClientName, sum(TransactionAmount) as amount
from t
group by `date`, ClientName
) t
group by `date`

Compare column from two rows and if different change values of another column

I have a table with an auto increment key id, item_no can be either one or two rows in a row (so they always have consecutive ids) that share the same ref but have different right/left (but technically item_no can be repeated multiple times throughout the table but that's not an issue), and description will sometimes be the same on the consecutive rows but sometimes different:
id | item_no | description | right\left | ref
1 | 1 | a1 | right | aaa
2 | 1 | a1 | left | aaa
3 | 2 | b1 | right | bbb
4 | 3 | c1 | right | ccc
5 | 3 | c2 | left | ccc
6 | 4 | d1 | right | ddd
7 | 4 | d1 | left | ddd
My issue is that I need item_no to append a -r or -l on to its value if the description of its 'matching' row is different.
So the result I am looking for is:
id | item_no | description | right\left | ref
1 | 1 | a1 | right | aaa
2 | 1 | a1 | left | aaa
3 | 2 | b1 | right | bbb
4 | 3-r | c1 | right | ccc
5 | 3-l | c2 | left | ccc
6 | 4 | d1 | right | ddd
7 | 4 | d1 | left | ddd
I am exporting the table to a csv but am not using much php, just a mysql statement and then looping out the results, is this possible within the mysql statement or will I have to rely on a php loop?
I would use this:
update
items inner join
(select item_no from items
group by item_no
having count(distinct description)>1) dup
on items.item_no=dup.item_no
set
items.item_no=concat(items.item_no, '-', substr(rightleft, 1,1))
If rows are always consecutive, you could also use this:
update
items i1 inner join items i2
on (i1.id=i2.id+1 or i1.id=i2.id-1)
and (i1.item_no=i2.item_no)
and (i1.description<>i2.description)
set i1.item_no=concat(i1.item_no, '-', substr(i1.rightleft, 1,1))
EDIT: if rows are always consecutive, and you just need a select and not an update, you could use this:
select
i1.id,
case when i1.description=i2.description or i2.id is null then i1.item_no else
concat(i1.item_no, '-', substr(i1.rightleft, 1,1)) end,
i1.description, i1.rightleft, i1.ref
from
items i1 left join items i2
on (i1.id=i2.id+1 or i1.id=i2.id-1) and (i1.item_no=i2.item_no)
order by i1.id
Try this:
SELECT
id,
CASE RightLeft
WHEN 'right' THEN CONCAT(item_no, '-r' )
WHEN 'left' THEN CONCAT(item_no, '-l' )
END AS item_no,
DESCRIPTION,
Rightleft,
ref
FROM Items
WHERE item_no IN
(
SELECT i1.item_no
FROM items i1
GROUP BY i1.item_no
HAVING(COUNT(DISTINCT description)) > 1);
SQL Fiddle Demo
This will give you:
| ID | ITEM_NO | DESCRIPTION | RIGHTLEFT | REF |
------------------------------------------------
| 4 | 3-r | c1 | right | ccc |
| 5 | 3-l | c2 | left | ccc |
I would rely on a PHP loop if you're using mysql, if you were using Oracle or SQL server then you could program a stored procedure.
You script should look something like this:
$dbh = new PDO('mysql:host='.DATABASE_HOST.';dbname='.DATABASE_NAME, DATABASE_USER, DATABASE_PASSWORD);
$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$data = $dbh->query("SELECT * FROM ExampleTable");
$dbh->beginTransaction();
foreach($data as $row)
{
$append = $row["right\left"] == "left" ? $row["item_no"]."-l" : $row["item_no"]."-r";
$stmnt = $dbh->prepare("UPDATE ExampleTable SET item_no = :item WHERE id = :id");
$stmnt->execute(array(":item" => $append,":id" => $row["id"]));
}
// Do some exception handling if something goes wrong you can allways do a rollback
// With PDO $dbh->rollBack();
$dbh->commit();
$dbh = null;
Something like this
UPDATE [dbo].[maTable] SET [item_no] = [item_no]+'r' WHERE not distinct [description] from [dbo].[maTable]
Should add an 'r' in the registration line where [description] is not identical (coded for SQL Server)

Categories