Alasql - group by and take the maximum result - sql

I have a table in the below format:
Vendor Id Weight
AAA 1 1234
AAA 1 121
AAA 2 5182
BBB 1 311
BBB 1 9132
BBB 2 108
I need to group by "Vendor" and "Id" and sum the "Weight". Whichever "Id" has the maximum "Weight" has to be assigned to the corresponding "Vendor". In the below example, Id "2" of Vendor "AAA" has a maximum weight of 5182 compared to the Id "1" whose weight is 1355 (1234+121). Hence Id "2" should be assigned to vendor "AAA". Similarly for Vendor "BBB", Id "1" has to be assigned as it has the maximum weight 9443 (311+9132) compared to Id "2" whose weight is "108".
Result has to be
Vendor Id
AAA 2
BBB 1
I am trying to implement this in "Alasql" which is the query language for Google Apps Script.
Any suggestions would be appreciated.

you can use window functions to do that:
select * from (
select Vendor,id,sum(weight) summWeight, row_number() over (order by sum(weight) desc) rn
from yourtable
group by Vendor,id
) tt
where rn = 1
then this is how you can do it:
select t.*
from (
select Vendor,max(summWeight) Maxweight from (
select Vendor,id,sum(weight) summWeight
from yourtable
group by Vendor,id
) tt
group by Vendor
) tt join (
select Vendor,id,sum(weight) summWeight
from yourtable
group by Vendor,id
) t
on t.vendor = tt.vendor
and summWeight = Maxweight

Related

sql : join table ,return record with count 1

I have a table mt table
It stores transactions.
Each transaction has a billing and its joined by external_id field
I want to return data from mt table where the billing table has only one joined record.
So in this case i would return (mttable, id:4 and 2. It's external_id 111 and 222 has only one record in billing table)
mt table
id external_id
--- -----------
1 444
2 222
3 333
4 111
billing table
id external_id
--- -----------
3 444
4 444
5 333
6 333
7 222
8 111
You could just use a basic GROUP BY query here:
SELECT mt.id, mt.external_id
FROM mt
INNER JOIN billing b ON b.external_id = mt.external_id
GROUP BY mt.id, mt.external_id
HAVING COUNT(*) = 1;
Demo
Hmmm . . .
select mt.*
from mt
where (select count(*)
from billing b
where mt.external_id = b.external_id
) = 1;
You can do something like the following:
SELECT * FROM mt WHERE external_id IN
(SELECT external_id FROM billing GROUP BY external_id HAVING COUNT(*) = 1)
There are few other options also, Like NOT EXISTS:
select t.*
from mt t join billing b on t.external_id = b.external_id
where not exists
(select 1 from billing bb
where mt.external_id = b.external_id and b.id <> bb.id);
Or You can also use the analytical function count as follows:
select * from
(select t.*, count(1) over (partition by b.external_id) as cnt
from mt t join billing b on t.external_id = b.external_id)
where cnt = 1

How to do rows to column in SQL Server with count

How do I simply switch Rows with Column in SQL with count? Is there any way to do?
Actually i want against each unique mobile no with count and product name side by side means if two mobile no in table then count = 2 and side of that two product1,product2 shows in output.
ie turn this result:
Srno Name| Mobile| Count | ProductName
1 xyz 1234 1 LNM
2 PQR 5678 1 VCD
3 xyz 1234 1 KLM
4 PQR 5678 1 NMG
into this:
Srno Name| Mobile| Count | ProductName1 | ProductName2
1 xyz 1234 2 LNM KLM
2 PQR 5678 2 VCD NMG
If you have a limited products then you use row_number() & do conditional aggregation :
select min(srno) as srno, name, Mobile, count(*) as cnt,
max(case when seq = 1 then ProductName end) as ProductName1,
max(case when seq = 2 then ProductName end) as ProductName2
from (select t.*,
row_number() over (partition by name, Mobile order by srno) as seq
from table t
) t
group by name, Mobile;
Try this:
SET #row_number = 0;
SELECT
(#row_number:=#row_number + 1) AS Srno,
T1.name,
T1.Mobile,
SUM(T1.xCount + T2.xCount) as cnt,
max(T1.ProductName) as Product1,
max(T2.ProductName) as Product2
FROM Table1 as T1
LEFT JOIN Table1 AS T2 ON T1.name = T2.name
AND T2.srno > T1.srno
GROUP BY T1.name, T1.Mobile
ORDER BY Srno

Find next row with specific value in a given row

The table I have now looks something like this. Each row has a time value (on which the table is sorted in ascending order), and two values which can be replicated across rows:
Key TimeCall R_ID S_ID
-------------------------------------------
1 100 40 A
2 101 50 B
3 102 40 C
4 103 50 D
5 104 60 A
6 105 40 B
I would like to return something like this, wherein for each row, a JOIN is applied such that the S_ID and Time_Call of the next row that shares that row's R_ID is displayed (or is NULL if that row is the last instance of a given R_ID). Example:
Key TimeCall R_ID S_ID NextTimeCall NextS_ID
----------------------------------------------------------------------
1 100 40 A 102 C
2 101 50 B 103 D
3 102 40 C 105 B
4 103 50 D NULL NULL
5 104 60 A NULL NULL
6 105 40 B NULL NULL
Any advice on how to do this would be much appreciated. Right now I'm joining the table on itself and staggering the key on which I'm joining, but I know this won't work for the instance that I've outlined above:
SELECT TOP 10 Table.*, Table2.TimeCall AS NextTimeCall, Table2.S_ID AS NextS_ID
FROM tempdb..#Table AS Table
INNER JOIN tempdb..#Table AS Table2
ON Table.TimeCall + 1 = Table2.TimeCall
So if anyone could show me how to do this such that it can call rows that aren't just consecutive, much obliged!
Use LEAD() function:
SELECT *
, LEAD(TimeCall) OVER (PARTITiON BY R_ID ORDER BY [Key]) AS NextTimeCall
, LEAD(S_ID) OVER (PARTITiON BY R_ID ORDER BY [Key]) AS NextS_ID
FROM Table2
ORDER BY [Key]
SQLFiddle DEMO
This is only test example I had close by ... but i think it could help you out, just adapt it to your case, it uses Lag and Lead ... and it's for SQL Server
if object_id('tempdb..#Test') IS NOT NULL drop table #Test
create table #Test (id int, value int)
insert into #Test (id, value)
values
(1, 1),
(1, 2),
(1, 3)
select id,
value,
lag(value, 1, 0) over (order by id) as [PreviusValue],
lead(Value, 1, 0) over (order by id) as [NextValue]
from #Test
Results are
id value PreviusValue NextValue
1 1 0 2
1 2 1 3
1 3 2 0
Use an OUTER APPLY to select the top 1 value that has the same R_ID as the first Query and has a higher Key field
Just change the TableName to the actual name of your table in both parts of the query
SELECT a.*, b.TimeCall as NextTimeCall, b.S_ID as NextS_ID FROM
(
SELECT * FROM TableName as a
) as a
OUTER APPLY
(
SELECT TOP 1 FROM TableName as b
WHERE a.R_ID = b.R_ID
AND a.Key > B.Key
ORDER BY Key ASC
) as b
Hope this helps! :)
For older versions, here is one trick using Outer Apply
SELECT a.*,
nexttimecall,
nexts_id
FROM table1 a
OUTER apply (SELECT TOP 1 timecall,s_id
FROM table1 b
WHERE a.r_id = b.r_id
AND a.[key] < b.[key]
ORDER BY [key] ASC) oa (nexttimecall, nexts_id)
LIVE DEMO
Note : It is better to avoid reserved keywords(Key) as column/table names.

Simply by the Query

Table name is group. Column name is groupno,name,grouprefno,detail,undergroupno
Sample data of group
groupno name grouprefno detail undergroupno
1 A 001 abc 0
2 B 002 cde 0
3 AA 001001 abc 1
4 AC 001002 abc 1
5 AAA 001001001 DDD 3
6 DDD 001001002 ddd 3
7 www 001002001 223 4
8 eee 001002002 222 4
Now i want to get rows which name's are AA, AC and which are comes under the AA,AC
So i tried like this
select no from group where substring(grouprefno,1,
(select length(grouprefno) from group where name ='AA'
))=(select grouprefno from group
where name ='AA' ) union all select no from group where substring(grouprefno,1,
(select length(grouprefno) from group where name ='AC'
))=(select grouprefno from group
where groupname ='AC' )
Its Work Fine, But i want another solution because it has 2 sub query's in side of single query. It has any other feasible solution?
Am using postgresql 9.1
Try:
WITH q AS(
SELECT *
FROM Table1
WHERE name IN ('AA','AC')
)
SELECT * FROM q
UNION ALL
SELECT * FROM Table1 t
WHERE t.undergroupno IN (
SELECT groupno FROM q
)
Demo: http://sqlfiddle.com/#!12/fce65/3

Within the same group find and exclude records that have the same parent ID for certain types

I have a table like following:
GroupID ParentID Type
1 ABC IND
1 ABC IND
1 CDE ORD
1 EFG STD
2 ZZZ IND
2 ZZZ IND
2 ZZZ IND
3 YYY COR
3 YYY COR
I need to exclude those records that are in the same group, having the same parent ID and the type is IND or COR. But I need to keep those groups that have different parent ID and the type is not IND or COR.
So the result I want to get would be the following:
GroupID ParentID Type
1 ABC IND
1 ABC IND
1 CDE ORD
1 EFG STD
Somehow I am thinking to use
Rank () over(partition by GroupID order by ParentID), but it won't give me the results that I want.
Any thoughts? PS: This table has 5 Million+ records. Looking for the effective way to deal with it.
Thanks
The following gives you a list of the groupIDs you want to exclude
SELECT GroupID
FROM
(
SELECT GroupID,
COUNT(DISTINCT ParentID) AS PCount, COUNT(DISTINCT TypeCode) as TCount,
MAX(TypeCode) AS tCode
FROM tablename
GROUP BY GroupID
) t
WHERE PCount = 1 AND TCount = 1
AND (tCode = 'IND' OR tCode = 'COR')
Now select everything else
SELECT *
FROM tableName
WHERE GroupID not in (
SELECT GroupID
FROM
(
SELECT GroupID,
COUNT(DISTINCT ParentID) AS PCount, COUNT(DISTINCT TypeCode) as TCount,
MAX(TypeCode) AS tCode
FROM tablename
GROUP BY GroupID
) t
WHERE PCount = 1 AND TCount = 1
AND (tCode = 'IND' OR tCode = 'COR')
)
Test with fiddle --> http://sqlfiddle.com/#!3/f1d4f/15/0
How is
1 ABC IND
in result set? here type is IND and you mentioned the result set should not have type IND or COR?