Thanks for any help in advance, I can't wrap my SQL skills around this one...
I have two tables like this:
Settings
Customerid ViewerLimit
1 50
2 50
Distribution
Customerid ServerIP
1 stream3
1 stream4
2 stream3
I want to calculate the load on each server. A customer divides the load if they have more than one server, so here customer 1 puts a load of 25 on each server. The result I'm trying to get is this:
ServerIP Load
stream3 75
stream4 25
I tried to do a sum function similar to this:
sum(viewerlimit/(count # of servers)) as load group by serverip
But I can't do a sub query within a sum function. There are many customers and possibly many servers per customer so it will become too complex to do manually. I appreciate any input.
Here is uninspired version with count in derived table:
select serverip, sum (viewerlimit/cast (ServerCount as float)) Load
from
(
select customerid, count(*) ServerCount from distribution group by customerid
) a
inner join settings
on a.customerid = settings.customerid
inner join distribution
on settings.customerid = distribution.customerid
group by serverip
Sql Fiddle to play around
UPDATE - an attempt at explanation
Derived tables are used to produce ad-hoc result sets that can be joined to main body of a query. It is placed in from clause and enclosed in parenthesis. You can use anything an ordinary select can use, top, order by, aggregate functions etc. The only thing you cannot use is correlation to a table in main body. Oh, and CTE. Derived table must be aliased.
In previous sample derived table 'a' selects counts of servers by customerid. Main body sees it as a table with CustomerId and ServerCount columns, ready to be used as any column from all listed tables. A join on customerid is performed between settings and 'a'. As this is 1:1 relation (both tables produce single row given a customerid), no duplication occurs.
How about doing a count of servers in a sub query and assign that to a query variable and then use that query variable inside the sum function?
select d.serverip, sum(s.viewerlimit/d.devider)
from (
select customerid, serverip, COUNT(serverip) over (partition by customerid) servercount
from distribution
) d
join settings s
on s.customerid=d.customerid
group by d.serverip
Related
I would like to iterate the same query while using different parameter values from a predefined list.
Say, I have a table with two columns. The first columns contains customer name. The second column contains customer spending.
###CUSTOMER; SPENDING###
customer1; 1000
customer2; 111
customer3; 100
customer1; 323
...
I know the complete list of customers: customerlist = {customer1, customer2, customer3}.
I would like to do something like:
Select sum(spending)
from mytable
where customer = #customerlist
The query should compute the sum of spending for each customer defined in the customer list. I have found some examples of sql procedures with stored parameters but not the case with one parameter of multiple values.
Thank you
P.S. This is just a hypothetical example to illustrate my question (I know it would be much more effective to use here a simple group by).
You can use nested query like this
SELECT CustomerList.CustomerName Cust, isnull((SELECT SUM(Spending) CustSpending
FROM Customer
WHERE Customer.CustomerName = CustomerList.CustomerName),0)
FROM CustomerList
This would normally be done using GROUP BY:
Select customer, sum(spending)
from mytable
group by customer;
GROUP BY is a very fundamental part of SQL. You should review your knowledge of SQL so you understand how to use it.
I am not even sure if I am asking this question correctly. Algorithmically I know what I want to do, but don't know the appropriate syntax in SQL.
I have created a table that contains total online session times by customer number, IP, session start time, and total session length. Here is an example of what this table looks like(ip and CustNo is masked, also not sure how to make tables so excuse the weirdness):
CustNo minDate maxDate ClientIp timeDiff
123456 2017-11-14-02:39:27.093 2017-11-14-02:39:59.213 1.1.1.1 0.000372
I then create another table looking for a specific type of activity and want to know how long this specific user has used that IP for before this specific activity. The second table contains each activity as a separate row, customerID, IP and a timestamp.
Up to here no issue and the tables look fine.
I now need to write the part that will look into the first table based on customer ID and IP, then sum all usage of that IP for that customer as long as session min start time is less than the activity time but I have no idea how to do this. Here is the current function (not working obviously). I am doing a left join because it is possible this will be a new IP and it may not be in the first table.
SELECT
*,
SUM(##finalSessionSums.timeDiff)
FROM
##allTransfersToDiffReceip
LEFT JOIN
##finalSessionSums ON ##allTransfersToDiffReceip.CustNo = ##finalSessionSums.CustNo
AND ##allTransfersToDiffReceip.ClientIp = ##finalSessionSums.ClientIp
AND ##allTransfersToDiffReceip.[DateTime] < ##finalSessionSums.minDate
I get an aggregate function error here but I don't know how to approach this at all.
You have a SELECT * (return all columns) and an aggregate function (In this case SUM). Whenever you combine specific columns for return alongside aggregate, summarised values you need to stipulate each column specified in the SELECT clause in the GROUP BY clause. For example
SELECT
A, B, SUM(C) as CSum
FROM
Table
GROUP BY
A, B
In cause of the few information, I can't provide a perfect solution, but I'll give it a try:
First, like Alan mentioned, you have to select only columns that you need for your aggregate-function, which is CustomerNo and Ip. To get the sums of the query, you have to group it like this:
SELECT sum(s.timeDiff) as Sum, s.custNo, s.Ip
FROM ##finalSessionSums s
INNER JOIN ##allTransfersToDiffReceip a on a.CustNo = s.CustNo
AND a.ClientIp = s.ClientIp
AND a.[DateTime] < s.minDate
GROUP BY s.custNo, s.Ip;
I am working with our inventory database and I created a query (access 2002 format citrix run server) that counts all items of a type meeting a serviceability status and it runs as I had expected but when I try to display the item name Equipment.Model in the other table which is already left joined via the ID I get the error Tried to execute a query that does not include the specified expression 'model' as part of an aggregate function. I think I would expect to get this if I tried to list something like an asset ID but this is related to the items I am counting. The trouble piece is quoted. The tables are quite large but they are basically the below
Equipment
|EquipmentID|CompanyID|Model|Description|TypeID|...
Inventory
|InventoryID|EquipmentID|Serial|Status|...
SELECT Inventory.EquipmentID, "Equipment.Model", COUNT(*) AS Count
FROM (Inventory LEFT JOIN Equipment ON Inventory.EquipmentID=Equipment.EquipmentID)
WHERE Equipment.TypeID = 14
AND Inventory.Status NOT IN (4,5,6,8)
GROUP BY Inventory.EquipmentID;
SELECT Inventory.EquipmentID, Equipment.Model, COUNT(*) AS Count
FROM Inventory
LEFT JOIN Equipment ON Inventory.EquipmentID=Equipment.EquipmentID
WHERE Equipment.TypeID = 14
AND Inventory.Status NOT IN (4,5,6,8)
GROUP BY Inventory.EquipmentID, Equipment.Model;
You have to use all non aggregate columns in the GROUP BY clause.
You need to include equipment.Model in your group by clause
I am joining 2 tables using Cartesian Product as follows.
select p.type, i.amount
FROM products p, invoice i
where (p.account = i.id); -- column headers cant be changed despite having same info
This of course displays 2 columns with the respective values.
However I then want to manipulate the data further using COUNT/GROUP BY and SUM/GROUP BY but have been unable to find any relevant examples which I could get to work using 2 tables. (doing them all separately is ok, just getting them to work together is the problem).
For the end result, I want to show 3 columns showing a grouping of the 4 types, with the count of the entries falling under each type, and the total amount/SUM for each type, eg.
Type - Count of Types - Total Value
A - 5 - 500
B - 6 - 1000
C - 1 - 50
D - 2 - 100
Did you try this?
select p.type, count(p.type) Cnt, sum(i.amoumt) Total
FROM products p, invoice i
where (p.account = i.id)
group by p.type
Bear in mind that the result of a query is logically equivalent to a table or a view -- all of them are a projection of zero or more rows with one or more columns.
In general what you can do to a table in terms of select you can also do to a query or a view. Despite some limitations you can also apply deletes and updates to views and queries just as you can to a table.
If in doubt, create the query that returns the data you want, and then treat it as a table:
select type,
count(type) count_type,
sum(amount) sum(amount)
from (select ... )
group by type
Note also the subquery factoring clause, which has particular appplications if you need to reference the same logical data set multiple times:
with my_data as(
select ... )
select type,
count(type) count_type,
sum(amount) sum(amount)
from my_data
where type in (select ... from my_data)
group by type
I am running the following queries against a database:
CREATE TEMPORARY TABLE med_error_third_party_tmp
SELECT `med_error_category`.description AS category, `med_error_third_party_category`.error_count AS error_count
FROM
`med_error_category` INNER JOIN `med_error_third_party_category` ON med_error_category.`id` = `med_error_third_party_category`.`category`
WHERE
year = 2003
GROUP BY `med_error_category`.id;
The only problem is that when I create the temporary table and do a select * on it then it returns multiple rows, but the query above only returns one row. It seems to always return a single row unless I specify a GROUP BY, but then it returns a percentage of 1.0 like it should with a GROUP BY.
SELECT category,
error_count/SUM(error_count) AS percentage
FROM med_error_third_party_tmp;
Here are the server specs:
Server version: 5.0.77
Protocol version: 10
Server: Localhost via UNIX socket
Does anybody see a problem with this that is causing the problem?
Standard SQL requires you to specify a GROUP BY clause if any column is not wrapped in an aggregate function (IE: MIN, MAX, COUNT, SUM, AVG, etc), but MySQL supports "hidden columns in the GROUP BY" -- which is why:
SELECT category,
error_count/SUM(error_count) AS percentage
FROM med_error_third_party_tmp;
...runs without error. The problem with the functionality is that because there's no GROUP BY, the SUM is the SUM of the error_count column for the entire table. But the other column values are completely arbitrary - they can't be relied upon.
This:
SELECT category,
error_count/(SELECT SUM(error_count)
FROM med_error_third_party_tmp) AS percentage
FROM med_error_third_party_tmp;
...will give you a percentage on a per row basis -- category values will be duplicated because there's no grouping.
This:
SELECT category,
SUM(error_count)/x.total AS percentage
FROM med_error_third_party_tmp
JOIN (SELECT SUM(error_count) AS total
FROM med_error_third_party_tmp) x
GROUP BY category
...will gives you a percentage per category of the sum of the categories error_count values vs the sum of the error_count values for the entire table.
another way to do it - without the temp table as seperate item...
select category, error_count/sum(error_count) "Percentage"
from (SELECT mec.description category
, metpc.error_count
FROM med_error_category mec
, med_error_third_party_category metpc
WHERE mec.id = metpc.category
AND year = 2003
GROUP BY mec.id
);
i think you will notice that the percentage is unchanging over the categories. This is probably not what you want - you probably want to group the errors by category as well.