SQL window function over partition by syntax error - sql

I have a test table with two columns brand and store
brand
store
A
a
A
b
B
a
I'm trying to use the window function to get the output like this
brand
store
num_stores
A
a
2
A
b
2
B
a
1
Here's what I've been trying on both presto sql and sqlite but keep getting "(" syntax error.
select brand, store,
count(store) OVER (PARTITION BY brand) as num_stores
from table
Struggling to find why I got this error and how to fix. Appreciate your help :))

It could be that your particular database does not support analytic functions. In that case, you could, as a workaround, try the following:
SELECT t1.brand, t1.store, t2.cnt AS num_stores
FROM yourTable t1
INNER JOIN
(
SELECT brand, COUNT(store) AS cnt
FROM yourTable
GROUP BY brand
) t2
ON t2.brand = t1.brand;

You can try with the below query:
select brand, store, count(*) OVER (PARTITION BY brand, store) as
num_stores from table;

You are missing () brackets for alias covering. You can check my query in db-fiddle
SELECT
Brand,
Store,
(COUNT(Store) OVER (PARTITION BY Brand)) as Num_Stores
FROM your_table

Related

Impala: all DISTINCT aggregate functions need to have the same set of parameters

I got the following error in my Impala query:
select
upload_key,
max(my_timestamp) as upload_time,
max(color_key) as max_color_fk,
count(distinct color_key) as color_count,
count(distinct id) as toy_count
from upload_table
group by upload_key
and got the error:
AnalysisException: all DISTINCT aggregate functions need to have the
same set of parameters as count(DISTINCT color_key); deviating
function: count(DISTINCT id)
I am not sure why I got this error. What I did was for each group (grouped by upload_key), I tried to compute how many distinct id as well as how many distinct color_key.
Does any one have any idea
The error message indicates that DISTINCT is only allowed on one column [combination], but you try two, color_key& id. A workaround would be two Selects and then a join:
select
t1.upload_key,
t1.upload_time,
t1.max_color_fk,
t1.color_count,
t2.toy_count
from
(
select
upload_key,
max(my_timestamp) as upload_time,
max(color_key) as max_color_fk,
count(distinct color_key) as color_count
from upload_table
group by upload_key
) as t1
join
(
select
upload_key
count(distinct id) as toy_count
from upload_table
group by upload_key
) as t2
on t1. upload_key = t2.upload_key

SQL: find most common values for specific members in column 1

I have the following SQL related question:
Let us assume I have the following simple data table:
I would like to identify the most common street address and place it in column 3:
I think this should be fairly straight-forward using COUNT? Not quite sure how to go about it though. Any help is greatly appreciated
Regards
This is a very long method that I just wrote. It only lists the most frequent address. You have to get these values and insert them into the table. See if it works for you:
select * from
(select d.company, count(d.address) as final, c.maxcount,d.address
from dbo.test d inner join
(select a.company,max(a.add_count) as maxcount from
(select company,address,count(address) as add_count from dbo.test group by company,address)a
group by a.company) c
on (d.company = c.company)
group by d.company,c.maxcount,d.address)e
where e.maxcount=e.final
Here is a query in standard SQL. It first counts records per company and address, then ranks them per company giving the most often occurring address rank #1. Then it only keeps those best ranked address records, joins with the table again and shows the results.
select
mytable.company,
mytable.address,
ranked.address as most_common_address
from mytable
join
(
select
company,
address,
row_number() over (partition by company oder by cnt desc) as rn
from
(
select
company,
address,
count(*) over (partition by company, address) as cnt
from mytable
) counted
) ranked on ranked.rn = 1
and ranked.company = mytable.company
and ranked.address = mytable.address;
This select statement will give you the most frequent occurrence. Let us call this A.
SELECT `value`,
COUNT(`value`) AS `value_occurrence`
FROM `my_table`
GROUP BY `value`
ORDER BY `value_occurrence` DESC
LIMIT 1;
To INSERT this into your table,
INSERT INTO db (col1, col2, col3) VALUES (val1, val2, A)
Note that you want that whole select statment for A!
You don't mention your DBMS. Here is a solution for Oracle.
select
company,
address,
(
select stats_mode(address)
from mytable this_company_only
where this_company_only.company = mytable.company
) as most_common_address
from mytable;
This looks a bit clumsy, because STATS_MODE is only available as an aggregate function, not as an analytic window function.

Transact-SQL query subtotal column

When my sql query returns the results it looks like this:
Driver Amount
A $120.00
A -$5.00
A $10.00
B $90.00
But now I've been requested to add a column to the query results that will present the total for each driver. So it should now look like this:
Driver Amount Subtotal
A $120.00 $125.00
A -$5.00 $125.00
A $10.00 $125.00
B $90.00 $90.00
Possible?
Use window functions.
with cte as (
<your query here>
)
select cte.*,
sum(amount) over (partition by driver) as subtotal
from cte;
You can probably incorporate this logic directly into the query that returns the first results as well.
Sorry that I can't provide you with the full query, but the following link may help accomplish what you need with GROUP BY and ROLLUP, if you're using MS SQL.
https://technet.microsoft.com/en-us/library/bb522495(v=sql.105).aspx
one other way of doing this would be to use CTE (Common Table Expression)
With cteName as (
Select DriverId,
Sum(DriverAmount) As TotalDriverAmount
FROM YourTable
GROUP BY DriverId
),
Select YourTable.DriverId, DriverAmount, cteName.TotalDriverAmount
FROM YourTable LEFT JOIN cteName ON(cteName.DriverId = YourTable.DriverId)
SELECT T.DRIVER, T.AMOUNT, S.TOT [SUBTOTAL] FROM YOURTABLE T JOIN
(SELECT DRIVER, SUM(AMOUNT) TOT FROM YOURTABLE GROUP BY DRIVER ) S
ON T.DRIVER = S.DRIVER
This should work on just about any MS-SQL version.
From
https://www.sqlservercentral.com/Forums/Topic1541134-3412-1.aspx
This is really easy thanks to some (Windowing) functionality born in 2005.
SELECT OrderNo
,Something
,Amount
,SubTotal = SUM(Amount) OVER (PARTITION BY OrderNo)
FROM #TestTable
ORDER BY OrderNo, Something
Create a function that get driver Id, query driver data and return total, call that function in query
Select DriverId, Amount, func(driverId) as TotalAmount
FROM Table
function func(ID){
return(Select sum(amount) from table where driverid=ID);
}

SQL query - percentage of sub sample

I got a SQL statement:
Select
ID, GroupID, Profit
From table
I now want to add a fourth column percentage of group profits.
Therefore the query should sum all the profits for the same group id and then have that number divided by the profit for the unique ID.
Is there a way to do this? The regular sum function does not seem to do the trick.
Thanks
select t1.ID,
t1. GroupID,
(t1.Profit * 1.0) / t2.grp_profit as percentage_profit
from table t1
inner join
(
select GroupID, sum(Profit) as grp_profit
from table
group by GroupID
) t2 on t1.groupid = t2.groupid
One more option with window function
select ID, GroupID, Profit * 1. / SUM(profit) OVER(PARTITION BY GroupID)
from t1
An alternative solution using scalar sub-queries is as follows:
select t1.ID, t1.GroupID, (select sum(t2.Profit) * 1.0 / t1.Profit
from table t2
where t2.GroupID = t1.GroupID) as percentage_profit
from table t1;
To provide an alternate answer, albeit less efficient, is to use a scalar subquery.
SELECT ID, GroupId, Profit, (Profit/(SELECT sum(Profit)
FROM my_table
WHERE GroupId= mt.GroupId))*100 as pct
FROM my_table as mt
From the way it reads I'm not sure if you want "percentage of group profits" or you or want group_profit / individual profit
That's the way this sounds "Therefore the query should sum all the profits for the same group id and then have that number divided by the profit for the unique ID"
Either way just switch the divisor for what you want!
Also if you're using Postgresql >= 8.4 you can use a window function.
SELECT ID, GroupId, Profit, (Profit/ (sum(Profit) OVER(partition by GroupId)))*100 as pct
FROM core_dev.my_table as mt

SELECT * WHERE val = MIN ( val )?

I'm fairly new to Oracle SQL, but already it's logic is beginning to confuse me. I'm trying to select all columns from a table where a particular column PRICE has the minimum value.
This works:
SELECT MIN(PRICE) FROM my_tab;
This returns me the minimum value. But why can't I select all the columns in that row? The following won't work:
SELECT * FROM my_tab WHERE PRICE = MIN( PRICE );
What am I missing here? Cheers folks!
*EDIT*
Here is the full code I'm having trouble with:
SELECT * FROM ( SELECT c.NAME, o.* FROM customers c JOIN customer_orders o ON c.CUST_NBR = o.CUST_NBR ) AS t WHERE t.PRICE = ( SELECT MIN( t.PRICE) FROM t );
SELECT * FROM TABLE WHERE PRICE = (SELECT MIN(PRICE) FROM TABLE)
--Edited
WITH
TABLE AS
(QUERY)
SELECT * FROM TABLE
WHERE PRICE = (SELECT MIN(PRICE) FROM TABLE)
You can also use a subquery to get the result:
select t1.*
from my_tab t1
inner join
(
SELECT MIN(PRICE) MinPrice
FROM my_tab
) t2
on t1.price = t2.minprice
See previous SO question, and especially answer by "Vash" which is best for your purposes. Note that you probably want to avoid a subselect since Oracle may be smart enough to use an index on the price if available to look at only one record.
Most databases, but apparently not Oracle, have either TOP 1 or LIMIT clauses for questions like these.