Is It Possible To Join Two Unrelated Tables In MySQL? - mysql

I have two unrelated tables but i want to join them into one query, is that possible?
This is how I did it using cross join but it did not work
table 1
| ID | Amount |
| 1 | 20 |
| 2 | 10 |
| 3 | 21 |
| 4 | 50 |
table 2
| ID | Paid Value |
| 011 | 5 |
| 052 | 2 |
//My tried Query
SELECT
a.`Amount`,
b.`Paid Value`
FROM
`table 1` a
CROSS JOIN
`table 2` b
This is what i get in return using the above query
| ID | Amount | Paid Value |
| 1 | 20 | 5 |
| 2 | 10 | 2 |
| 3 | 21 | 5 |
| 4 | 50 | 2 |
However this is my expected results
| ID | Amount | Paid Value |
| 1 | 20 | 5 |
| 2 | 10 | 2 |
| 3 | 21 | 0 |
| 4 | 50 | 0 |

You want to join by some implicit row number. Let me assume that this is based on the ordering of the ids. You can use variables to calculate the row number and then use that for the join:
select t1.id, t1.amount, coalesce(t2.paidvalue, 0)
from (select t1.*, (#rn := #rn + 1) as rn
from table1 t1 cross join
(select #rn := 0) vars
order by id
) t1 left join
(select t2.*, (#rn2 := #rn2 + 1) as rn
from table1 t2 cross join
(select #rn2 := 0) vars
order by id
) t2
on t1.rn = t2.rn;

Related

SQL query to get minimal sum value and associated column from table

I have following tables:
t1 - Items
| Id | Item |
| 1 | I1 |
| 2 | I2 |
t2 - Item_elements
| Id | Item_id | Element | Our_quantity | Client_quantity |
| 1 | 1 | E11 | 100 | 0 |
| 2 | 1 | E12 | 20 | 300 |
| 3 | 2 | E21 | 300 | 100 |
| 4 | 2 | E22 | 5 | 300 |
t3 - Element_operations
| Id | Element_id | Operations_number |
| 1 | 1 | 100 |
| 2 | 1 | 50 |
| 3 | 2 | 50 |
| 4 | 2 | 50 |
| 5 | 3 | 50 |
| 6 | 3 | 50 |
| 7 | 3 | 50 |
| 8 | 3 | 50 |
| 9 | 4 | 10 |
I need SQL query which return table witch items (t1) AND element row associated with item table which has minimum operations number
Desired Output:
Table should look like
| Id|Item| Id_el |Our_quantity| Client_quantity | Count Operations_number|
| 1| I1 | 2 | 20 | 300 | 100 |
| 2| I2 | 4 | 5 | 300 | 10 |
result
I tried that query
SELECT t2.Id,Item_id,Our_Quantity,Client_Quantity,SUM(Operations_number)
FROM t2 LEFT JOIN t3 ON t2.Id=t3.Id_el GROUP BY t2.Id)
Tried Result:
| Id | Item_id | Our_quantity | Client_quantity |SUM(Operations_number)
| 1 | 1 | 100 | 0 | 150
| 2 | 1 | 20 | 300 | 100
| 3 | 2 | 300 | 100 | 200
| 4 | 2 | 5 | 300 | 10
What should I do next?
Now I have 2 table:
| Element Id | Item_id |Sum operations_number for element |
| 1 | 1 | 150 |
| 2 | 1 | 100 |
| 3 | 2 | 200 |
| 4 | 2 | 10 |
| Item Id | Item |
| 1 | I1 |
| 2 | I2 |
How can I join them to get this table?
Item Element who has minimal sum operations number.
| Item Id | Item | Element_Id | Sum operations_number for element |
| 1 | I1 | 2 | 100 |
| 2 | I2 | 4 | 10 |
You could get desired output using this..
SELECT
t.*,
MIN(t.opsum) AS `Count Operations_number`
FROM
(SELECT
a.*,
b.Id AS `Id_el`,
b.`Our_quantity`,
b.`Client_quantity`,
SUM(c.`Operations_number`) AS opsum
FROM
`t1` AS a
LEFT JOIN `t2` AS b
ON a.`Id` = b.`Item_id`
LEFT JOIN `t3` AS c
ON b.`Id` = c.`Element_id`
GROUP BY a.Id,
b.Id
ORDER BY a.`Id` ASC,
opsum ASC) AS t
GROUP BY t.Id ;
FIDDLE HERE
Maybe if you use the MIN() method in the desired column, as example:
SQL
SELECT t2.Id,Item_id, MIN(Our_Quantity), Client_Quantity, SUM(Operations_number)
FROM t2 LEFT JOIN t3
ON t2.Id=t3.Id_el
GROUP BY t2.Id
You may try this..
For mysql 8+
with cte as (
SELECT t1.id as Item_id, t1.item, t2.id as Ele_Id, t2.Element , t2.Our_quantity , t2.Client_quantity , t3.Operations_number
from Items as t1
inner join Item_elements as t2 on t1.id=t2.Item_id
inner join Item_elements as t3 on t2.id = t3.Element_id
)
, ct as (
select row_number() over ( partition by t1.id order by t2.Our_quantity ) as Slno, * from cte
)
select c.item_id, c.item, c.Ele_id, c.Element, c.our_quantity, c.client_quantity, t.Count_Operations_number
from ct as c
inner join
(
select distinct Element_id , sum(Operation_number) as Count_Operations_number
from Element_operations group by Element_id
) as t
on c.Ele_id=t.Element_id
where c.slno=1
Try the below query, hope this is what you are asking
select t1.Id as 'Id',t1.Item as 'Item',
t.Id as 'Id_el', t.Our_quantity as 'Our_quantity',t.Client_quantity as 'Client_quantity',
sum(t3.Operations_number) as 'Count Operations_number'
from t1 join (select *
from t2 where (Item_id,Our_quantity) in
( select Item_id, min(Our_quantity) from t2 group by Item_id)) t on t1.Id=t.Item_id
join t3 on t.Id=t3.Element_id
group by t1.Id;
Do you want it in the minimum order of SUM(Operations_number)?
Try this
I have updated the answer so this will get the first table also.
SELECT t1.id,
t1.item,
id_el,
our_quantity,
client_quantity,
sum
FROM t1
JOIN (SELECT t2.id AS Id_el,
t2.item_id,
t2.our_quantity AS our_quantity,
t2.client_quantity AS client_quantity,
sum
FROM t2
JOIN (SELECT t3.element_id,
Sum(operations_number) AS sum
FROM t3
GROUP BY element_id) AS b
ON t2.id = b.element_id) AS c
ON t1.id = c.item_id
ORDER BY sum ASC
Output would be:

mysql, update foreach category

it is a really simple question. it is only 1 table!
i have a table of books which each book have a category and a number.
SO I WANNA TRANSFORM THIS
+--------------------------+
| book_id | category | num |
+--------------------------+
| 1 | a | 7 |
| 2 | a | 5 |
| 3 | a | 3 |
| 4 | b | 9 |
| 5 | b | 8 |
| 6 | b | 1 |
+--------------------------+
INTO THIS,
+--------------------------+
| book_id | category | num |
+--------------------------+
| 3 | a | 3 |
| 2 | a | 5 |
| 1 | a | 7 |
| 6 | b | 1 |
| 5 | b | 8 |
| 4 | b | 9 |
+--------------------------+
AND THEN THIS!
+--------------------------+
| book_id | category | num |
+--------------------------+
| 3 | a | 1 |
| 2 | a | 2 |
| 1 | a | 3 |
| 6 | b | 1 |
| 5 | b | 2 |
| 4 | b | 3 |
+--------------------------+
BUT HOW?!?!?!?!
script to create table...
drop table if exists books;
CREATE TABLE books(
id int AUTO_INCREMENT,
category varchar(30),
num int,
PRIMARY KEY (id)
);
insert into books (category,num)
values
('a',7),
('a',5),
('a',3),
('b',9),
('b',8),
('b',1);
You can use user variables to generate the sequence numbers within each category in the order of increasing id.
If you just want to query the table, use:
select
b.id,
b.category,
#rn := if(#category = category, #rn + 1, if (#category := category, 1, 1)) num
from books b, (select #category := null, #rn := 0) t2
order by b.category, b.id
If you want to update your table, use:
update books b1
join (
select
b.id,
#rn := if(#category = category, #rn + 1, if (#category := category, 1, 1)) num
from books b, (select #category := null, #rn := 0) t2
order by b.category, b.id
) b2 on b1.id = b2.id
set b1.num = b2.num;
Demo
EDIT:
As per the edited question, you can use order by b.category, b.num instead.

Merge column of two tables without relationship

I need to merge columns of two tables with different rows. It should put NULL value into table with less rows.
Example :
Assume these two simple tables :
table_one
+----+-----------+---------------------+
| id | title | date |
+----+-----------+---------------------+
| 10 | Good | 2014-10-08 05:13:00 |
| 11 | NotBad | 2014-10-24 00:00:00 |
| 12 | Excellent | 2014-10-26 14:00:00 |
| 13 | Bad | 2014-10-11 19:31:23 |
+----+-----------+---------------------+
table_two
+----+------+
| id | name |
+----+------+
| 1 | Sara |
| 2 | Alex |
+----+------+
What output I need :
+----+-----------+---------------------+------+------+
| id | title | date | id | name |
+----+-----------+---------------------+------+------+
| 10 | Good | 2014-10-08 05:13:00 | 1 | Sara |
| 11 | NotBad | 2014-10-24 00:00:00 | 2 | Alex |
| 12 | Excellent | 2014-10-26 14:00:00 | NULL | NULL |
| 13 | Bad | 2014-10-11 19:31:23 | NULL | NULL |
+----+-----------+---------------------+----+------+
What I've tried so far :
SELECT table_one.*, table_two.* FROM table_one, table_two
But that's not my desire! It will return Cartesian Product
P.S :
These two tables has not any relationship between each other.
If you assume the first table has more rows, you can do this by generating a key using variables:
select t1.*, t2.*
from (select t1i.*, (#rn1 := #rn1 + 1) as rn
from table_one t1i cross join (select #rn1 := 0) vars
) t1 left join
(select t2i.*, (#rn2 := #rn2 + 1) as rn
from table_two t2i cross join (select #rn2 := 0) vars
) t2
on t1.rn = t2.rn;
You will have two surplus columns called rn, if you don't need that, list your columns instead of select t1.*, t2.*.

Sum up values from rows in MySQL table

I have added a new column 'sums' to my table and I am trying to sum up values from 'vals' column then update 'sums' in the same table, according to the algorithm shown below in the table.
I could write a few loops in PHP but I don't think it would be nice.
Any clue how to write it nicely?
--------------------------------------------------
| id | sets | parts | vals | sums |
|-------|---------|---------|----------|---------|
| 1 | 1 | 1 | 2 | 2 |
|-------|---------|---------|----------|---------|
| 2 | 1 | 2 | 3 | 2+3=5 |
|-------|---------|---------|----------|---------|
| 3 | 1 | 3 | 5 |2+3+5=10 |
|-------|---------|---------|----------|---------|
| 4 | 2 | 1 | 4 | 4 |
|-------|---------|---------|----------|---------|
| 5 | 2 | 2 | 1 | 4+1=5 |
|-------|---------|---------|----------|---------|
| 6 | 2 | 3 | 2 | 4+1+2=7 |
|-------|---------|---------|----------|---------|
| 7 | 3 | 1 | 6 | 6 |
|-------|---------|---------|----------|---------|
This should return the value you want for sums:
SELECT t.id
, IF(t.sets=#prev_sets,#i:=#i+t.vals,#i:=t.vals) AS `sums`
, #prev_sets := t.sets AS prev_sets
FROM mytable t
JOIN (SELECT #prev_sets := NULL, #i := 0 ) i
ORDER BY t.sets, t.parts
You can use this as an inline view in an update statement
UPDATE ( SELECT t.id
, IF(t.sets=#prev_sets,#i:=#i+t.vals,#i:=t.vals) AS `sums`
, #prev_sets := t.sets AS prev_sets
FROM mytable t
JOIN (SELECT #prev_sets := NULL, #i := 0 ) i
ORDER BY t.sets, t.parts
) s
JOIN mytable r
ON r.id = s.id
SET r.sums = s.sums
From the example data, it looks like you want the "groupings" on sets, and you want to order on parts within each group.

MySQL SUM with same ID

Sorry for the real simple question, I just learn PHP & MySQL, I already googling it for more than a week but I didn't found any answer.
I create a simple finance script and the table is like below :
table_a
aid | value
1 | 100
2 | 50
3 | 150
table_b
bid | aid | value
1 | 1 | 10
2 | 1 | 15
3 | 2 | 5
4 | 2 | 10
5 | 3 | 25
6 | 3 | 40
I want the result like this
No | ID | Total | Balance
1 | 1 | 10 | 90
2 | 1 | 25 | 75
3 | 2 | 5 | 45
4 | 2 | 15 | 35
5 | 3 | 25 | 125
6 | 3 | 65 | 85
Can anybody help me with my problem?
Thanks
Try this running total: http://www.sqlfiddle.com/#!2/ce765/1
select
bid as no, value,
#rt := if(aid = #last_id, #rt + value, value) as total,
#last_id := aid
from table_b b, (select #rt := 0 as x, #last_id := null) as vars
order by b.bid, b.aid;
Output:
| NO | VALUE | TOTAL | #LAST_ID := AID |
|----|-------|-------|-----------------|
| 1 | 10 | 10 | 1 |
| 2 | 15 | 25 | 1 |
| 3 | 5 | 5 | 2 |
| 4 | 10 | 15 | 2 |
| 5 | 25 | 25 | 3 |
| 6 | 40 | 65 | 3 |
Then join to table A, final query:
select x.no, x.aid, x.value, x.total, a.value - x.total as balance
from
(
select
bid as no, aid, value,
#rt := if(aid = #last_id, #rt + value, value) as total,
#last_id := aid
from table_b b, (select #rt := 0 as x, #last_id := null) as vars
order by b.bid, b.aid
) as x
join table_a a using(aid)
Output:
| NO | AID | VALUE | TOTAL | BALANCE |
|----|-----|-------|-------|---------|
| 1 | 1 | 10 | 10 | 90 |
| 2 | 1 | 15 | 25 | 75 |
| 3 | 2 | 5 | 5 | 45 |
| 4 | 2 | 10 | 15 | 35 |
| 5 | 3 | 25 | 25 | 125 |
| 6 | 3 | 40 | 65 | 85 |
Live test: http://www.sqlfiddle.com/#!2/ce765/1
UPDATE
Not dependent on column bid sorting, running total on grouping will not be impacted: http://www.sqlfiddle.com/#!2/6a1e6/3
select x.no, x.aid, x.value, x.total, a.value - x.total as balance
from
(
select
#rn := #rn + 1 as no, aid, value,
#rt := if(aid = #last_id, #rt + value, value) as total,
#last_id := aid
from table_b b, (select #rt := 0 as x, #last_id := null, #rn := 0) as vars
order by b.aid, b.bid
) as x
join table_a a using(aid)
Output:
| NO | AID | VALUE | TOTAL | BALANCE |
|----|-----|-------|-------|---------|
| 1 | 1 | 10 | 10 | 90 |
| 2 | 1 | 15 | 25 | 75 |
| 3 | 1 | 7 | 32 | 68 |
| 4 | 2 | 5 | 5 | 45 |
| 5 | 2 | 10 | 15 | 35 |
| 6 | 3 | 25 | 25 | 125 |
| 7 | 3 | 40 | 65 | 85 |
Live test: http://www.sqlfiddle.com/#!2/6a1e6/3
SELECT
tb.bid as No,
ta.aid as ID,
tb.value as Total,
ta.value-tb.total as Balance
FROM
table_a AS ta
INNER JOIN (
SELECT
tbx.aid AS aid,
tbx.bid AS bid,
tbx.value AS value,
SUM(tby.value) AS total
FROM
table_b AS tbx
INNER JOIN table_b AS tby ON tby.aid=tbx.aid AND tby.bid<=tbx.bid
GROUP BY tbx.bid
ORDER BY tbx.bid
) AS tb ON tb.aid=ta.aid
ORDER BY tb.bid
As #Quassnoi pointed out, this is not very efficient with MySQL. I tried to use a freak join instead of a subquery, as the inner query might be of use in its own right.
Edit
Took some interest in this and found the join version to be twice as fast as the subquery version by #Quassnoi ... anybody having an idea why this would be?
Edit
Answer to the second question (in comment below):
SELECT
table_a.aid AS aid,
SUM(table_b.value) AS Total,
table_a.value-SUM(table_b.value) AS Balance
FROM
table_a
INNER JOIN table_b ON table_a.aid=table_b.aid
GROUP BY table_a.aid
You are looking for analytics functions. Unfortunately, MySQL lacks them.
You can implement it in a less efficient way:
SELECT bid, aid, total, value - total
FROM (
SELECT b.bid, b.aid, COALESCE(a.value, 0) AS value,
(
SELECT SUM(value)
FROM b bp
WHERE bp.aid = b.aid
AND bp.bid <= b.bid
) AS total
FROM b
LEFT JOIN
a
ON a.aid = b.aid
) q