SQL - apply single value to all rows in table - sql

I have two tables - one called "customer_data" and one called "weighted_average_rate_charged".
Customer_data
First Name
Last Name
City
Daily_Rate
Total_paid
Jim
Carter
Dallas
$100.00
$600.00
James
Franklin
Houston
$150.00
$900.00
Lily
Smith
Dallas
$90.00
$540.00
Frank
Masters
Dallas
$95.00
$680.00
Jennifer
Brown
Houston
$100.00
$590.00
Weighted_Average_Rate_Charged
I have used the following query:
select
City,
sum(Daily_Rate * Total_Paid)/sum(Total_Paid) as WA_Rate
from customer_data
group by
City
To get my weighted average per city. Now, what i want to do is take the max number, which according to the output below is 130.2013:
City
WA_Rate
Houston
$130.2013
Dallas
$95.1648
And essentially create a new table which is the same as customer_data but with an additional column called "Max_WA_daily" which shows $130.2013 for all entries in that table.
Example:
First Name
Last Name
City
Daily_Rate
Total_paid
Max_WA_daily
Jim
Carter
Dallas
$100.00
$600.00
$130.2013
James
Franklin
Houston
$150.00
$900.00
$130.2013
Lily
Smith
Dallas
$90.00
$540.00
$130.2013
Frank
Masters
Dallas
$95.00
$680.00
$130.2013
Jennifer
Brown
Houston
$100.00
$590.00
$130.2013
I have tried a range of different join options and nested select statements, but cant get this to work. Any ideas please?

We could use analytic functions here, with a two tier aggregation approach:
WITH cte AS (
SUM(Daily_Rate * Total_Paid) OVER (PARTITION BY City) /
SUM(Total_Paid) OVER (PARTITION BY City) AS WA_Rate_City
FROM customer_data
)
SELECT First, Last, City, Daily_Rate, Total_Paid,
MAX(WA_Rate_City) OVER () AS Max_WA_daily
FROM cte;
The first CTE turns out the WA rates partitioned by each city. The query below that finds the max such value, but across the entire table.

Windows functions can be used here. It allows us to have aggregations on different levels within one view [table] which you need.
Additionally, I would suggest not to use Subquery and use Common Table Expressions (CTE)
Step 1: Calculate the weighted average [the one you already did]
Explaination of Step 1:
Here in the OVER() clause you have defined the aggregation level just like you did in the group by above. Which means you can still select all the other colums [first name, last name, daily rate, total paid and NOT have them in the Partition BY clause [the beauty of windows functions]. In windows functions you define the aggregation layer within Partition by which is City in your case)
STEP 2: Get Max() Value [The one you need]
Explaination: here we didn't add the aggregation layer as we just need the max value from the column weighted average.Hence partition by and OVER is left empty
With Weighted_Average AS (
Select
city,
first_name,
last_name,
city,
daily_rate,
total_paid,
sum(daily_rate * total_paid) OVER(PARTITION BY city)
/
sum(total_paid) OVER(PARTITION BY city) AS weighted_average
FROM
customer_data
group by
city
)
Select
*,
MAX(weighted_average) OVER() AS max_weighted_average
FROM
Weighted_Average

select
City,sum(Daily_Rate*Total_paid)/sum(Total_Paid) as WA_Rate
from customer_data
group by City
select ,
(select sum(Daily_RateTotal_paid)/sum(Total_Paid) as WA_Rate from customer_data
where City in ('Dallas')
group by City) as Max_WA_Rate from customer_data

Try the Following
select FistName,LastName,City,Daily_Rate,Total_Paid,
(select max(WA_Rate) from Weight_Average) as Max_Wa_Rate
from customer_data

Related

How to make a raw SQL query that selects the city with the highest population associated with an area code (there are duplicate area codes)

I have a table that has the following columns:
areaCode
zipcode
city
state
population
There are multiple rows with the same area codes that are associated with different cities/zip codes.
I need to select the city with the highest population that corresponds to the area code.
EX:
area_codes / zip / city / state / population
858 94111 San Francisco CA 3905
858 94121 San Francisco CA 34786
914 10010 New York NY 22785
914 10012 New York NY 17738
I want to be able to only select the city San Francisco (with area code of 858) that has the population of 34786 and the row New York (with area code of 914) that has the population of 22785, since they have the highest populations. After selecting these ones I need to create a new table and place them in a new table.
Try This:
Create table MaxPopulation as (select area_codes,city,max(population) from table group by area_codes,city);
A general solution uses ROW_NUMBER:
WITH cte AS (
SELECT *, ROW_NUMBER() OVER (PARTITION BY area_codes ORDER BY population DESC) rn
FROM yourTable
)
SELECT area_codes, zip, city, state, population
FROM cte
WHERE rn = 1;
INSERT INTO cte_new
SELECT
area_codes,
zip,
city,
state,
MAX(population) population
FROM cte
GROUP BY
area_codes,
zip,
city,
state
Generally I would prefer a grouping function than a window function (parition) since it offers a much better performance. I have skipped the table declaration that you would require before this code

How to find people in a database who live in the same cities?

I'm new to SQL, and I'm asking for help in an apparently easy question, but it gets cumbersome in my mind.
I have the following table:
ID NAME CITY
---------------------
1 John new york
2 Sam new york
3 Tom boston
4 Bob boston
5 Jan chicago
6 Ted san francisco
7 Kat boston
I want a query that returns all the people who live in a city that another person registered in the database also lives in.
The answer, for the table I showed above, would be:
ID NAME CITY
---------------------
1 John new york
2 Sam new york
3 Tom boston
4 Bob boston
7 Kat boston
This is really a two part question:
What cities have more than one user located in them?
What users live in that subset of cities?
Let's answer it in two parts. Let's also make the simplifying assumption (not stated in your question) that the Users table has only one entry per user per city.
To find cities with more than one user:
SELECT City FROM Users GROUP BY City HAVING COUNT(*) > 1
Now, let's find all the users for those cities:
SELECT ID, User, City FROM Users
WHERE City IN (SELECT City FROM Users GROUP BY CITY HAVING COUNT(*) > 1)
I would use EXISTS :
SELECT t.*
FROM table t
WHERE EXISTS (SELECT 1 FROM table t1 WHERE t1.city = t.city AND t1.name <> t.name);
To avoid a correlated subquery which leads to a nested loop, you could perform a self join:
SELECT id, name, city
FROM persons
JOIN (SELECT city
FROM persons
GROUP BY city HAVING count(*) > 1) AS cities
USING (city);
This might be the most performant solution.
This will give you the rows that have the same city more than 1 time:
SELECT persons.*
FROM persons
WHERE (SELECT COUNT(*) FROM persons AS p GROUP BY CITY HAVING p.CITY = persons.CITY) > 1
This is just a different flavor from the others that have posted.
SELECT ID,
name,
city
FROM (SELECT DISTINCT
ID,
name,
city,
COUNT(1) OVER (PARTITION BY city) AS cityCount
FROM table) t
WHERE cityCount > 1
This can be expressed many ways. Here is one possible way:
select * from persons p
where exists (
select 1 from persons p2
where p2.city = p.city and p2.name <> p.name
)

return max purchase from column and group by country?

I am looking to group by country and find the max purchase
related to that country.
SELECT
country ,
customer_name,
total_purchased
FROM total
GROUP BY 1,2
ORDER BY 1
output:
country customer_name total_purchased
Australia Diego GutiƩrrez 39.6
Australia Mark Taylor 81.18
Austria Astrid Gruber 69.3
Belgium Daan Peeters 60.3899999
Brazil Alexandre Rocha 69.3
Brazil Eduardo Martins 60.39
I am looking for a way to return the best customer of the country. Best customer means the person of the country who spend more money.
Eg: In australia there are two person I want the table with one australia and a customer with max purchase. How can I do it? I tried but I couldn't figure out a way so far.
Desired output:
country customer_name total_purchased
Australia Mark Taylor 81.18
Austria Astrid Gruber 69.3
Belgium Daan Peeters 60.3899999
Brazil Eduardo Martins 60.39
I don't know which version of SQL are you using but analytics functions can help you although are not available in old MySQL versions.
If you CAN use analytics functions, something like this might work:
SELECT country,
customer_name,
total_purchased
FROM (
SELECT
country,
customer_name,
total_purchased,
RANK() OVER (PARTITIONED BY country ORDER BY total_purchased DESC) as rank
FROM total
) a
WHERE rank = 1
If you can't use analytics functions you can do something like this:
SELECT a.country,
a.customer_name,
a.total_purchased
FROM total a
JOIN (
SELECT
country,
MAX(total_purchased) AS max_purchased
FROM total
GROUP BY country
) b
ON a.country = b.country
AND a.total_purchased = b.max_purchased
This query should have the expected result. In case 2 customers have the same total_purchased value. The result will show both customers.

SQL Subquery or Group BY to return Distinct values of a certain column?

I am running into an issue where I know I am close to a solution but I cannot get the right data to come back or am getting errors on the queries.
Basically what I want to do is to select values from a single table based on the following: I want them based on an employee name I supply and I want them to return DISTINCT Account Numbers for that employee(sometimes the same account number is listed more than one time...I only want one row of data from each duplicate account number).
Here is what I have tried so far:
SELECT DISTINCT * FROM Employees WHERE EmpName = 'Mary Johnson' GROUP BY AccountID
-This returns an error saying I don't have an aggregate for the column EmployeeID(which isn't a calculated column, so why is it asking for an aggregate??)
Then I tried a subquery:
SELECT EmployeeID, EmpName, Department, Position, (SELECT DISTINCT AccountID From Employees) AS AcctID FROM Employees WHERE EmpName = 'Mary Johnson'
-This gives me an error saying AT Most one record can be returned(I'm in Access).
I know there has to be a solution to what I am looking for---Currently If I do a full query just on EmpName it returns 30 records, however, 23 of them have a duplicate AccountID, so there should only be 7 records that return with a DISTINCT AccountID.
How can I achieve this via SQL?
Here is an Example:
ID(PK) EmpName AcctID Department Position EmpId
------ -------- --------- -------- -------- ------
1 Mary Johnson 1234 IT Tech 226663
2 Mary Johnson 1234 IT Tech 226663
3 Mary Johnson 1234 IT Tech 226663
4 Mary Johnson 2345 IT Tech 226663
5 John James 23442 Banking Teller 445645
6 Jame Tabor 1234 HR Manager 234555
In the example above I want to do an SQL Query to get the rows back with the AccountId's for Mary Johnson that are DISTINCT. So We would get back 2 rows Mary Johnson 1234 and Mary Johnson 2345, ignoring the other 2 rows that Mary Johnson has with duplicate AccountIDs of 1234 and the other rows with employees not named Mary Johnson
This is not really easy to do in MS Access -- it lacks row_number(). One method is to use another column that uniquely identifies each row that has the same AccountID:
select e.*
from Employees as e
where e.?? = (select max(e2.??)
from Employees as e2
where e2.AccountId = e.AccountId and e2.empName = e.empName
);
The ?? is for the column that uniquely identifies the rows.
If you only care about two columns, then use select distinct:
select distinct e.empName, e.AccountId
from employees as e;
You an add a where clause to either query to restrict to a single employee. However, it doesn't make sense to me that a table called Employees would have multiple rows for a single employee name (except in the rare case of people with the same names).
The reason you are getting the error about "you can only return one row" is because you are using a subquery to feed into a record row. In that case, you are searching for distinct AcctIDs for Mary Johnson, she has two distinct ones, so the query fails. If you used MIN(AcctID) that query would work fine. Therefore, this will work:
SELECT EmployeeID, EmpName, Department, Position, MIN(AccountID )
FROM Employees
WHERE EmpName = 'Mary Johnson'
GROUP BY EmployeeID, EmpName, Department, Position
The next question you need to ask yourself is WHICH AccountID do you want to see? You can switch to MAX, but if you have three values and you want the middle one, that will be a lot harder to solve. But, the above query will at least give you a working result.
EDIT:
That should give you only one row assuming you have identical information for Mary Johnson. If you are getting 24 it means you have different entries For empname, department, position, or employeeid. If you want to see all AccountIDs associated with Mary Johnson, use this:
SELECT EmployeeID, MIN(EmpName), AccountID, MIN(Department) AS Department, MIN(Position) AS Position
FROM Employees
WHERE EmpName = 'Mary Johnson'
GROUP BY EmployeeID, AccountID

SQL: Select distinct one column but include all fields

How can I select distinct one column (user) and then output the rest of the fields based on this one column?
Input:
user age country
--------------------------------
Tom 34 US
Tom 32 EN
Dick 29 MX
Dick 29 DE
Harry 15 CA
output (distinct user column, and pick one row to output for rest of fields):
user age country count
--------------------------------------
Tom 34 US 2
Dick 29 MX 2
Harry 15 CA 1
Any help would be appreciated!
SELECT USER, AGE, MAX(COUNTRY), COUNT(*)
FROM TABLE
GROUP BY USER, AGE
You could try changing the MAX for a MIN. No need for a DISTINCT here.
You could use some data format like SUBSTRING, but I'm not sure if the rest of the data will always be like that US and USS etc. Buy if you have more than 2/3 or if the changes start beyond a specific character you may encounter some wrong query results.
According to comments and updates.
SELECT USER, MAX(AGE), MAX(COUNTRY), COUNT(*)
FROM TABLE
GROUP BY USER.
SELECT user, age, country, COUNT(*) AS c_rec FROM
(
SELECT DISTINCT user, age, SUBSTRING(country, 1, 2) AS country FROM yourTable
) T
GROUP BY user, age, country