How to use MySQL UNION and SUM in views - mysql

I have 2 tables
table one :
id amount
1 2
1 1
2 1
table two :
id amount
1 2
I want make view with the output like this :
view :
id amount
1 5
2 1
I tried with my simple code like this
CREATE VIEW v_test AS
SELECT id, sum(amount)
FROM table1
UNION ALL
SELECT id, sum(amount)
FROM table2
GROUP BY id
but when i run the SQL above the output like this :
id amount
1 2
1 3
2 1
any code for the output that i want?
thanks

Looking to your data sample and do the fact that some mysql version don't allow subselect in view you can create a utility view
create view v_test_union
as
select id, amount
from table1
union all
select id, amount
from table2
then create your view
create view
as
select id, sum(amount)
from v_test_union
If you use mysql 5.7 or above, you can use subquery in the create view statement:
create view
as
select id, sum(amount)
from
(select id, amount
from table1
union all
select id, amount
from table2) t
group by id

you can also use this by using join like below
CREATE VIEW v_test AS
SELECT table1.id as id,(sum(table1.amount)+sum(table2.amount)) as amount FROM table1
join table2 on table1.id=table2.id
GROUP BY table1.id

SQL DEMO
CREATE VIEW v_test AS
SELECT id, SUM(amount)
FROM (
SELECT id, amount
FROM table1
UNION ALL
SELECT id, amount
FROM table2
) t
GROUP BY id
;
OUTPUT

Related

Get records as per the given ids' mysql

This is the query i am executing
SELECT email,firstname,lastname FROM `sco_customer`
WHERE id_customer IN (7693,7693,7693,7693,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,7693,3,3,3,3,3,7693,7693,3,3,3,7693,3,3,3)
This gives me only two records as their are same number of id_customer is filtered i.e 7693,3
email firstname lastname
abc#any.com Test Mage
abc2#any.com User Mage
It should give the same number of records as much is the id_customer
Any thoughts how this can be achieved ?
Try below. Instead of WHERE clause you can generate a dummy table and join it with your main table.(WITH works for version 8 or above)
WITH SAMPLE AS
(
SELECT 7693 AS ID FROM DUAL
UNION ALL
SELECT 3 AS ID FROM DUAL
)
SELECT email,firstname,lastname FROM `sco_customer`
INNER JOIN SAMPLE ON SAMPLE.ID=ID_CUSTOMER
Below mysql version 8:
SELECT email,firstname,lastname FROM `sco_customer`
INNER JOIN (
SELECT 7693 AS ID FROM DUAL
UNION ALL
SELECT 3 AS ID FROM DUAL
)SAMPLE ON SAMPLE.ID=ID_CUSTOMER
The following statement should solve you problem:
SELECT email,firstname,lastname FROM `sco_customer`
join (select 7693 as id_customer union all
select 7693 union all
select 7693 union all
select 3 union all
select 3 union all
select 3
) tmp on sco_customer.id_customer = tmp.id_customer

MySql: How to select rows where all values are the same?

I have a table like this:
name |id | state
name1 12 4
name1 12 4
name2 33 3
name2 33 4
...
I want to select every name and id from table where state is only 4, that means name1 is correct, because it only has two records with state 4 and nothing more. Meanwhile name2 is wrong, because it has record with state 4 and record with state 3.
You can use aggregation as shown below:
SELECT name, id
FROM your_table
GROUP BY name, id
HAVING SUM(state<>4)=0;
See a Demo on SQL Fiddle.
select name, id from mytable where id not in
(select distinct id from mytable where state <> 4)
you might need 2 sub queries .
select with group by name were state 4
select with group by name
compare the count if the count is same then select it
example : select name , count (name) from table where state = 4 as T1
select name , count (name) from table as T2
select T1.name from T1 and T2 where T2.count = T1.count
You can use not exists like this:
select distinct name, id
from table1 a
where not exists (select *
from table1 b
where a.id=b.id and state<>4)
In a more general case you can use count distinct (with not exists or with a join):
select distinct name, id
from table1 a
where not exists (
select *
from table1 b
where a.id=b.id
group by id
HAVING count(distinct state)>1)

MySQL UNION SELECT and IN clause

I have two very simple table: t1 and t2 with the following rows:
table t1:
id, name
1 PBN
table t2:
id, name
100 FIBERHOME
Query 1:
SELECT name FROM t1 UNION SELECT name FROM t2 WHERE id IN (1)
Result is: PBN
Query 2:
SELECT name FROM t1 UNION SELECT name FROM t2 WHERE id IN (100)
Result is: PBN, FIBERHOME
But the expected result is: FIBERHOME..! What is the reason?
To expand on #Knep's answer, if you only want one WHERE id IN ():
SELECT name FROM (
SELECT id, name FROM t1
UNION
SELECT id, name FROM t2
) unioned
WHERE id IN (1,100)
Probably not great speed wise, so best to test.
Note also the id needs to be in the sub query to be used in the outer WHERE.
I thought that the WHERE clause is global – #szpal
To answer the question as to why the WHERE isn't used for all queries in the UNION, think about two queries that don't share a column.
On their own:
SELECT id, name FROM x WHERE colA = 123
And:
SELECT id, name FROM y WHERE colB = 456
Then together with (the incorrect) single WHERE clause:
SELECT id, name FROM x
UNION
SELECT id, name FROM y
WHERE colB = 456 -- But table x doesn't have a colB!
Whereas if (correctly) the WHERE clause sits with each query:
SELECT id, name FROM x
WHERE colA = 123 -- I have a colA, still don't have a colB
UNION
SELECT id, name FROM y
WHERE colB = 456 -- I have a colB, still don't have a colA
Everyone's a winner!
UNION sum up the two results.
In the first query, there is no condition so it returns PBN, then it adds the result of the second result FIBERHOME.
Using UNION you could try:
SELECT name FROM t1 WHERE id IN (100) UNION SELECT name FROM t2 WHERE id IN (100)
The where condition in second query will be executed before union.
SELECT name FROM t1
will return
id name
1 PBN
SELECT name FROM t2 WHERE id IN (100)
will return
id name
null null
The union will combine above two results as
SELECT name FROM t1 UNION SELECT name FROM t2 WHERE id IN (100)
id name
1 PBN
You can solve this by
SELECT
name
FROM
(SELECT
*
FROM
interns_test_db.t1 UNION SELECT
*
FROM
interns_test_db.t2) A
WHERE
ID IN (100)
But this may reduce the performance.

Mysql union select error

I am trying to display all records from table1 even if the catid not existing in table2 (all employee in table2 should have all catid from table1 with 0 days if not exising in table2) with the following sql query but getting an error
Error Code: 1054. Unknown column 'catid' in 'group statement'
select empid,days from table2 union select catid from
table1 group by empid, catid;
table1:
catid
1
2
3
table2:
empid catid days (computed column count(*))
1000 1 8
1000 3 10
expected result:
empid catid days
1000 1 8
1000 2 0 <---catid 2 and days 0 if catid not existing in table2 for empid 1000
1000 3 10
That is not the function of the union statement. Union statement does a set like capability which merging two sets. What you are looking for a is a join with the table 1 where you do a count and group by catid. Your data model to achieve this output itself is grievously wrong ;)
select employeeid, catid, sum(days) from table1, table2 group by employeeid, catid;
You just need a LEFT JOIN:
Select tab2.empid, tab2.catid, ifnull(tab2.days, 0)
from tab2
left join tab1 on tab2.catid = tab1.catid
Please note : While doing a UNION the number and type of the columns present in the first select should be the same as the next Selects.
So you need to first make the select columns in sync first.
can you check this and add empid similarly.
SELECT TABLE1.CATID, IFNULL(TABLE2.DAYS,0) FROM table1 LEFT OUTER JOIN
table2 ON table1.catid = table2.catid
Please use LEFT JOIN with IFNULL.
Select table2.empid, table1.catid, IFNULL(table2.days, 0) from table2
LEFT JOIN table1 ON table2.catid = table1.catid;

Using SUM() without grouping the results

I already read (this), but couldn't figure out a way to implement it to my specific problem. I know SUM() is an aggregate function and it doesn't make sense not to use it as such, but in this specific case, I have to SUM() all of the results while maintaining every single row.
Here's the table:
--ID-- --amount--
1 23
2 11
3 8
4 7
I need to SUM() the amount, but keep every record, so the output should be like:
--ID-- --amount--
1 49
2 49
3 49
4 49
I had this query, but it only sums each row, not all results together:
SELECT
a.id,
SUM(b.amount)
FROM table1 as a
JOIN table1 as b ON a.id = b.id
GROUP BY id
Without the SUM() it would only return one single row, but I need to maintain all ID's...
Note: Yes this is a pretty basic example and I could use php to do this here,but obviously the table is bigger and has more rows and columns, but that's not the point.
SELECT a.id, b.amount
FROM table1 a
CROSS JOIN
(
SELECT SUM(amount) amount FROM table1
) b
You need to perform a cartesian join of the value of the sum of every row in the table to each id. Since there is only one result of the subselect (49), it basically just gets tacked onto each id.
With MS SQL you can use OVER()
select id, SUM(amount) OVER()
from table1;
select id, SUM(amount) OVER()
from (
select 1 as id, 23 as amount
union all
select 2 as id, 11 as amount
union all
select 3 as id, 8 as amount
union all
select 4 as id, 7 as amount
) A
--- OVER PARTITION ID
PARTITION BY which is very useful when you want to do SUM() per MONTH for example or do quarterly reports sales or yearly...
(Note needs distinct it is doing for all rows)
select distinct id, SUM(amount) OVER(PARTITION BY id) as [SUM_forPARTITION]
from (
select 1 as id, 23 as amount
union all
select 1 as id, 23 as amount
union all
select 2 as id, 11 as amount
union all
select 2 as id, 11 as amount
union all
select 3 as id, 8 as amount
union all
select 4 as id, 7 as amount
) OverPARTITIONID
Join the original table to the sum with a subquery:
SELECT * FROM table1, (SELECT SUM(amount) FROM table1 AS amount) t
This does just one sum() query, so it should perform OK:
SELECT a.id, b.amount
FROM table1 a
cross join (SELECT SUM(amount) as amount FROM table1 AS amount) b
in case someone else has the same problem and without joining we can do the following
select *
,totcalaccepted=(select sum(s.acceptedamount) from cteresult s)
, totalpay=(select sum(s.payvalue) from cteresult s)
from cteresult t
end
Using Full Join -
case when you need sum of amount field from tableB and all data from tableA on behalf of id match.
SELECT a.amount, b.* FROM tableB b
full join (
select id ,SUM(amount) as amount FROM tableA
where id = '1' group by id
) a
on a.id = b.id where a.id ='1' or b.id = '1' limit 1;