SQL sum rows in union - mysql

I'm trying to SUM two rows obtained from differente SQL queries in UNION, is this possible?
All I can achieve is the two separate rows but I can't SUM them, DB engine keeps me telling that there's an error in the syntax near the *) FROM (the part next to the SUM)...
Here's the query:
SELECT * FROM
(SELECT COUNT(*) as cntclients
FROM
(SELECT DISTINCT clientkey AS clients
FROM <table>
WHERE <conditions...>)
) AS clients
) cntclients
UNION
(SELECT SUM(occurrences) AS cntclientsad
FROM <table2>
WHERE <conditions...>
)
This throws me for example:
cntclients
----------
901
50
Adding a SELECT SUM(*) FROM instead of the SELECT * FROM in the first line, and surrounding the two queries with parentheses just throws me the mentioned error...
I would like
cntclients <- or whatever name...
----------
951
Any ideas how this sum should work?

You don't actually need to use a UNION for this - you can just add them together manually:
SELECT a.countKey + b.sumOccur as total
FROM (SELECT COUNT(DISINCT clientkey) as countKey
FROM <table>
WHERE <conditions>) as a
CROSS JOIN (SELECT SUM(occurrences) as sumOccur
FROM <table2>
WHERE <conditions>) as b

select SUM(cntcol)
from
(
select count(*) as cntcol from sometables
union all
select SUM(occurrances) as cntcol from somemoretables
) ctquery

If you want to stick with the UNION you can write it this way:
SELECT sum(c.cntclients) as Totalcntclients
FROM
(
SELECT COUNT(*) as cntclients
FROM
(SELECT DISTINCT clientkey AS clients
FROM <table>
WHERE <conditions...>
) AS clients
UNION
SELECT SUM(occurrences) AS cntclientsad
FROM <table2>
WHERE <conditions...>
) c

You could also use:
SELECT
( SELECT COUNT(DISTINCT clientkey) as countKey
FROM <table>
WHERE <conditions>
)
+
( SELECT SUM(occurrences) as sumOccur
FROM <table2>
WHERE <conditions>
)
AS total

The approach that I took for this was to create a View for the UNION query. Then you can simply use
SELECT SUM(cntclients) FROM <view>

Related

SQL Union Query - Referencing to alias of derived table

I have a complicated aggregate-functions query that produces a result-set, and which has to be amended with a single row that contains the totals and averages of that result-set.
My idea is to assign an alias to the result-set, and then use that alias in a second query, after a UNION ALL statement.
But, I can't successfully use the alias, in the subsequent SELECT statement, after the UNION ALL statement.
For the sake of simplicity, I won't post the original query here, just a simplified list of the variants I've tried:
SELECT * FROM fees AS Test1 WHERE Percentage = 15
UNION ALL
(SELECT * FROM fees AS Test2 WHERE Percentage > 15)
UNION ALL
(SELECT * FROM (SELECT * FROM fees AS Test3 WHERE Percentage < 10) AS Test4)
UNION ALL
SELECT * FROM Test3
The result is:
MySQL said: Documentation
#1146 - Table 'xxxxxx.Test3' doesn't exist
The result is the same if the last query references to the table Test1, Test2, or Test4.
So, how should I assign an alias to a result-set/derived table in earlier queries and use that same alias in latter queries, all within a UNION query?
Amendment:
My primary query is:
SELECT
COALESCE(referrers.name,order_items.ReferrerID),
SUM(order_items.quantity) as QtySold,
ROUND(SUM((order_items.quantity*order_items.price+order_items.shippingcosts)/((100+order_items.vat)/100)), 2) as TotalRevenueNetto,
ROUND(100*SUM(order_items.quantity*order_items.purchasepricenet)/SUM((order_items.quantity*order_items.price+order_items.shippingcosts)/((100+order_items.vat)/100)), 1) as PurchasePrice,
ROUND(100*SUM(order_items.quantity*COALESCE(order_items.calculatedfee,0)+order_items.quantity*COALESCE(order_items.calculatedcost,0))/SUM((order_items.quantity*order_items.price+order_items.shippingcosts)/((100+order_items.vat)/100)), 1) as Costs,
ROUND(100*SUM(order_items.calculatedprofit) / SUM( (order_items.quantity*order_items.price + order_items.shippingcosts)/((100+order_items.vat)/100) ) , 1) as Profit,
COALESCE(round(100*Returns.TotalReturns_Qty/SUM(order_items.quantity),2),0) as TotalReturns
FROM order_items LEFT JOIN (SELECT order_items.ReferrerID as ReferrerID, sum(order_items.quantity) as TotalReturns_Qty FROM order_items WHERE OrderType='returns' and OrderTimeStamp>='2017-12-1 00:00:00' GROUP BY order_items.ReferrerID) as Returns ON Returns.ReferrerID = order_items.ReferrerID LEFT JOIN `referrers` on `referrers`.`referrerId` = `order_items`.`ReferrerID`
WHERE ( ( order_items.BundleItemID in ('-1', '0') and order_items.OrderType in ('order', '') ) or ( order_items.BundleItemID is NULL and order_items.OrderType = 'returns' ) ) and order_items.OrderTimestamp >= '2017-12-1 00:00:00'
GROUP BY order_items.ReferrerID
ORDER BY referrers.name ASC
I want to make a grand-total of all the rows resulting from query above with:
SELECT 'All marketplaces', SUM(QtySold), SUM(TotalRevenueNetto), AVG(PurchasePrice), AVG(Costs), AVG(Profit), AVG(TotalReturns) FROM PrimaryQuery
I want to do this with a single query.
Your query is well-written. You may be able to get a total line by using a surrounding query with a dummy GROUP BY clause and WITH ROLLUP:
SELECT
COALESCE(Referrer, 'All marketplaces'),
SUM(QtySold) AS QtySold,
SUM(TotalRevenueNetto) AS TotalRevenueNetto,
AVG(PurchasePrice) AS PurchasePrice,
AVG(Costs) AS Costs,
AVG(Profit) AS Profit,
AVG(TotalReturns) AS TotalReturns
FROM
(
SELECT
COALESCE(referrers.name,order_items.ReferrerID) AS Referrer,
SUM(order_items.quantity) AS QtySold,
...
) PrimaryQuery
GROUP BY Referrer ASC WITH ROLLUP;
I'm not entirely sure what you are attempting to solve, but I guess something like the following:
Hypothetical 'main' query:
SELECT T1.ID
, Sum(total_grade)/COUNT(subjects) as AverageGrade
FROM A_Table T1
JOIN AnotherTable T2
ON T2.id = T1.id
GROUP BY T1.ID
You want sub resultsets, without having to keep querying the same data.
Edit: I mistakenly thought the linked documentation and method mentioned below was for the current version of mySQL. It is however a draft for a future version, and CTE's are not currently supported.
In the absence of CTE support, I would probably just insert the resultset into a temporary table. Something like:
CREATE TABLE TEMP_TABLE(ID INT, AverageGrade DECIMAL(15, 3))
INSERT INTO TEMP_TABLE
SELECT T1.ID
, Sum(total_grade)/COUNT(subjects) as AverageGrade
FROM A_Table T1
JOIN AnotherTable T2
ON T2.id = T1.id
GROUP BY T1.ID
SELECT ID, AverageGrade FROM TEMP_TABLE WHERE AverageGrade > 5
UNION ALL
SELECT COUNT(ID) AS TotalCount, SUM(AverageGrade) AS Total_AVGGrade FROM TEMP_TABLE
DROP TABLE TEMP_TABLE
(Disclaimer: I'm not too familiar with mySQL, there may be some syntax errors here. The general idea should be clear, though.)
That is, of course, if i had to do it like this, there are probably better ways to achieve the same. See Thorsten Kettner's comments on the matter.
(Previous answer assuming CTE is a posibility:)
A CTE approach looks like:
WITH CTE AS
(
SELECT T1.ID
, Sum(total_grade)/COUNT(subjects) as AverageGrade
FROM A_Table T1
JOIN AnotherTable T2
ON T2.id = T1.id
GROUP BY T1.ID
)
SELECT ID, AverageGrade FROM CTE WHERE AverageGrade > 5
UNION ALL
SELECT COUNT(ID) AS TotalCount, SUM(AverageGrade) AS Total_AVGGrade FROM CTE
You have the error because every query involved in UNION doens't know the alias of other.
DB Engine execute, in your case, 4 queries and then paste them with UNION operation.
Your real table is fees. Test3 is an alias used in the third query.
If you want to process the results of UNION operation, you must encapsulate your queries in a MAIN query.
It looks like you need something like below. Please try
SELECT * FROM fees AS Test2 WHERE Percentage >= 15
UNION ALL
SELECT * FROM fees AS Test3 WHERE Percentage < 10
You can't use a table alias based on a subquery (is not in the scope of the outer united select) you must repeat the code eg:
SELECT * FROM fees AS Test1 WHERE Percentage = 15
UNION ALL
SELECT * FROM fees AS Test2 WHERE Percentage > 15
UNION ALL
SELECT * FROM (
SELECT * FROM fees AS Test3 WHERE Percentage < 10
) AS Test4
UNION ALL
SELECT * FROM fees AS Test3 WHERE Percentage < 10

SQL - Select multiply conditions

I would like to select multiply conditions using below query:
SELECT (SELECT count(*)
FROM users
)
as totalusers,
(SELECT sum(cashedout)
FROM users
) AS cashedout,
(SELECT COUNT(*)
FROM xeon_users_rented
) AS totalbots,
(SELECT sum(value)
FROM xeon_stats_clicks
WHERE typ='3' OR typ='1'
) AS totalclicks
The above query takes just under a second (0.912 to be exact) to execute. This slows things down a lot with thousands of requests.
What seems logical for me is this approach:
SELECT (SELECT count(*), sum(cashedout)
FROM users
)
as totalusers, cashedout,
(SELECT COUNT(*)
FROM xeon_users_rented
) AS totalbots,
(SELECT sum(value)
FROM xeon_stats_clicks
WHERE typ='3' OR typ='1'
) AS totalclicks
However that doesn't work, as I get the following error:
#1241 - Operand should contain 1 column(s)
Furthermore, how can I join the two other tables "xeon_users_rented" and "xeon_stats_clicks" in my first query?
It's slow because you have multiple subqueries. Try using joins instead.
Also, a list of your tables, columns would help us better assist you.
Your 2nd query is using wrong syntax, it should be
SELECT
count(*) as totalusers,
sum(cashedout) cashedout,
(SELECT COUNT(*) FROM xeon_users_rented) AS totalbots,
(SELECT sum(value) FROM xeon_stats_clicks
WHERE typ='3' OR typ='1') AS totalclicks
FROM users

How to get AS two separate selectors with UNION?

As sadly SQL is my weakest skill.
I'm trying to use UNION in a VIEW, where I can get statistics from two different tables with one query.
SELECT COUNT(*) AS `customer_count` FROM `Customers`
UNION
SELECT COUNT(*) AS `supplier_count` FROM `Suppliers`;
[Demo table]
However, it only returns customer_count, with two rows. Is there anyway, to make this work, so it returns customer_count and supplier_count separately?
You would need a cross join to see the results adjacent to each other in one row. So you would select from both the tables without a join condition.
select * from
(select count(*) as customer_count from Customers) x,
(select count(*) as supplier_count from Suppliers) y
select
(SELECT COUNT(*) FROM Customers) as customer_count,
(SELECT COUNT(*) FROM Suppliers) AS supplier_count
Using your Table Demo.
The key is use alias so the field names match on each union select.
In this case TableSource and Total
SELECT 'Customer' as TableSource, Count(City) as Total FROM Customers
UNION
SELECT 'Suppliers' as TableSource, Count(City) as Total FROM Suppliers;
CREATE VIEW `vw_count` AS
select (select count(0) from `tbl`) AS `customer_count`,
(select count(0) from `tbl2`) AS `supplier_count`;

Mysql Union in different columns

I have the following query
SELECT *
FROM(
(SELECT
MAX(c.start_time) as start_1
FROM
c1 c)
UNION ALL
(SELECT
MAX(cc.created_at) as ccmax
FROM
cc1)
) as t
I'd like to have the result in a table with 2 columns start_1 and cmax instead of the single column I get with all the different results listed.
How should I do it? I ended up in a subselect believing this would have done the job.
For the data to be in two columns you would have to use a sub select.
SELECT
MAX(c1.start_time) as start_1, (SELECT MAX(cc1.created_at) FROM cc1) as ccmax
FROM c1

How to get row count of 2 different tables (and databases) in one query?

I got a database named accounts and account table inside of this database, Also I got the database named players and player table inside of this database.
How can I get a rows count of this two tables in one query?
I've tried this:
SELECT
SUM(`account`.`account`.`id`) AS 'accounts',
SUM(`player`.`player`) AS 'players';
But it doesn't work.
If you need exactly rows count (not sum), than do something like this:
select
(select count(*) from accounts.account) as count1,
(select count(*) from players.player) as count2
or
select count(*) as `count`,"account" as `table` from accounts.account
union all
select count(*) as `count`,"player" as `table` from players.player
A simple UNION operation on two select statements will do:
SELECT COUNT(*), 'Accounts' FROM Accounts.Account
UNION
SELECT COUNT(*), 'Players' FROM Players.Player
And you have to qualify each table with the database name since they're in separate databases.
Try:
SELECT
COUNT(`account`.`id`) AS 'accounts',
COUNT(`player`.`player`) AS 'players'
FROM
`account`,
`player`
SELECT COUNT(*)
FROM (
SELECT Id
FROM accounts.account
UNION ALL
SELECT player
FROM players.player ) AS BothTables
with Value (nbr, name ) as
(
select count(*) amount, 'AccountsCount' as ab from accounts..account
union all
select count(*) amount, 'PlayersCount' as ab from players..player
)
select *
from value as s
PIVOT(sum(nbr) for name in (AccountsCount, PlayersCount) ) as pvt