Order By Sums, while not grouping like rows - sql

Suppose I have data that looks like this as the result of a query
SKU | STOCK | SNACK | FLAVOR
1234 45 Chips BBQ
1236 87 Chips BBQ
2345 12 Pretzel Bacon
3456 51 Chips Ranch
4567 32 Pretzel Classic
5678 142 Candy Chocolate
... ... ... ...
Is it possible to have SQL in an ORDER BY line that allows me to display the above data first sorted by whatever Snack (Chips, Pretzel, Candy, etc.) has the largest SUM(Stock) and then by Stock DESC while not merging any of the entries? I briefly tried to use a line similar to
ORDER BY
SUM(Snack) DESC,
SUM(Flavor) DESC,
Stock DESC
but could not determine how the GROUP BY statement should be laid out.

You can use DSum to compute total STOCK for each SNACK without a GROUP BY. And use that Dsum in the ORDER BY. I also needed to use Val() on the DSum values to make it sort correctly.
SELECT y.SKU, y.STOCK, y.SNACK, y.FLAVOR
FROM YourTable AS y
ORDER BY
Val(DSum("[STOCK]", "YourTable", "[SNACK]='" & y.SNACK & "'")) DESC,
y.STOCK DESC;
Be aware that DSum is Access-specific so this is not suitable if you want a query which can be ported to another database.

Try with following SQL
select sku, stock, data.snack, flavor, summ = summ.summ
from data
join (select snack, summ = sum(stock) from data group by snack) as summ
on summ.snack = data.snack
order by summ desc, stock desc
SKU|STOCK|SNACK|FLAVOR|SUMM
1236 87 Chips BBQ 183
3456 51 Chips Ranch 183
1234 45 Chips BBQ 183
5678 142 Candy Chocolate 142
4567 32 Pretzel Classic 44
2345 12 Pretzel Bacon 44

Related

Postgres rank() without duplicates

I'm ranking race data for series of cycling events. Racers win various amounts of points for their position in races. I want to retain the discrete event scoring, but also rank the racer in the series. For example, considering a sub-query that returns this:
License #
Rider Name
Total Points
Race Points
Race ID
123
Joe
25
5
567
123
Joe
25
12
234
123
Joe
25
8
987
456
Ahmed
20
12
567
456
Ahmed
20
8
234
You can see Joe has 25 points, as he won 5, 12, and 8 points in three races. Ahmed has 20 points, as he won 12 and 8 points in two races.
Now for the ranking, what I'd like is:
Place
License #
Rider Name
Total Points
Race Points
Race ID
1
123
Joe
25
5
567
1
123
Joe
25
12
234
1
123
Joe
25
8
987
2
456
Ahmed
20
12
567
2
456
Ahmed
20
8
234
But if I use rank() and order by "Total Points", I get:
Place
License #
Rider Name
Total Points
Race Points
Race ID
1
123
Joe
25
5
567
1
123
Joe
25
12
234
1
123
Joe
25
8
987
4
456
Ahmed
20
12
567
4
456
Ahmed
20
8
234
Which makes sense, since there are three "ties" at 25 points.
dense_rank() solves this problem, but if there are legitimate ties across different racers, I want there to be gaps in the rank (e.g if Joe and Ahmed both had 25 points, the next racer would be in third place, not second).
The easiest way to solve this I think would be to issue two queries, one with the "duplicate" racers eliminated, and then a second one where I can retain the individual race data, which I need for the points break down display.
I can also probably, given enough effort, think of a way to do this in a single query, but I'm wondering if I'm not just missing something really obvious that could accomplish this in a single, relatively simple query.
Any suggestions?
You have to break this into steps to get what you want, but that can be done in a single query with common table expressions:
with riders as ( -- get individual riders
select distinct license, rider, total_points
from racists
), places as ( -- calculate non-dense rankings
select license, rider, rank() over (order by total_points desc) as place
from riders
)
select p.place, r.* -- join rankings into main table
from places p
join racists r on (r.license, r.rider) = (p.license, p.rider);
db<>fiddle here

Complex multi level hierarchical SQL

How can I achieve the below results using a query in SQL Server.
Table: shares_info
Complex multilevel hierarchy:
comp_name investee
APPLE MS
APPLE INTEL
APPLE MRF
APPLE GOOG
MS GOOG
MS MRF
MRF STF
MRF ABC
GOOG INTEL
GOOG TRF
GOOG XYZ
The idea is something like this. APPLE has invested in MS,INTEL,MRF,GOOG. And so on. Now the below input is something like sell my shares but first sell off shares without dependencies first. That is what my output conveys. If I want to sell GOOG shares then based on my below input GOOG has dependency on INTEL/TRF/XYZ and hence before selling GOOG I need to sell (123, XYZ) and (456 INTEL). Next, if I want to sell APPLE it has dependency on MS/INTEL/MRF/GOOG and hence as per below input I need to first sell INTEL/MRF/GOOG to sell off APPLE.
Table: shares_sell_info
Some input
id comp_name
123 APPLE
456 APPLE
123 XYZ
789 GOOG
456 INTEL
243 MRF
432 ABC
The ordering should be like below
123 XYZ (XYZ does not have any dependency and hence should come at the top)
432 ABC (MRF has a dependency on ABC and hence ABC comes on top)
243 MRF (MRF’s dependency is all taken care and hence we have MRF)
456 INTEL (APPLE and GOOGLE has a dependency on INTEL and hence INTEL is on top)
789 GOOG (At this point we can add GOOG because all its dependents are already at top)
123 APPLE (APPLE has a dependency on GOOG and hence GOOG come before APPLE)
456 APPLE
In the above ordering one among XYZ/ABC could have been first and it does not matter because they both do not have any dependency
dbfiddle
WITH
cte_com as (SELECT * FROM (VALUES
(123 ,'APPLE'),
(456 ,'APPLE'),
(123 ,'XYZ'),
(789 ,'GOOG'),
(456 ,'INTEL'),
(243 ,'MRF'),
(432 ,'ABC')) as cte_com(id, comp))
,cte_temp as (SELECT * FROM (VALUES
('APPLE', 'MS'),
('APPLE', 'INTEL' ),
('APPLE', 'MRF' ),
('APPLE', 'GOOG' ),
('MS', 'GOOG' ),
('MS', 'MRF' ),
('MRF', 'STF' ),
('MRF', 'ABC' ),
('GOOG', 'INTEL' ),
('GOOG', 'TRF' ),
('GOOG', 'XYZ')) as cte_temp(one, two))
SELECT id, comp , one
, count(*) as count
from cte_com
left join cte_temp on cte_temp.one=cte_com.comp
group by id, comp, one
order by count(*)
But it's unclear why this solution gives the ordering you want.
What is the difference between 'XYZ' and 'ABC'?
They are both depending on 1 other comp.
output:
id comp one count
123 XYZ 1
432 ABC 1
456 INTEL 1
243 MRF MRF 2
789 GOOG GOOG 3
123 APPLE APPLE 4
456 APPLE APPLE 4
7 rows
I think #Luuk's idea is right with some slight modifications. Here is the query which worked for me.
select * from shares_sell_info as ssi
left join (
select comp_name, count(*) as count
from shares_info si
group by comp_name
UNION
select comp_name, 0 as count
from shares_info
where investee is null
) temp on temp.comp_name = share_info.comp_name
where id in (
)
order by count
Here is the actual answer for my problem that I got from another post.
https://stackoverflow.com/questions/60420380/assign-weight-based-on-hierarchical-depth

SQL query to allow NULL for a highest_bid column when no bid has been placed yet

For school I need to make a function on an auction website. For this I need to join a couple of tables in a VIEW. This worked just fine, until I needed to add a filter for price range. Seems easy enough but the query result needs to allow a NULL when no bid has been placed.
The Statement for the View:
SELECT I.itemID, I.title, I.startPrice, B.highestBid, Cfi.category, I.endDate
FROM dbo.Items AS I INNER JOIN dbo.category_for_item AS Cfi ON V.itemID = Vir.itemID
LEFT OUTER JOIN dbo.Bid AS B ON V.itemID = B.itemID
This would get the following Table:
itemID title startPrice highestBid category endDate
1 1234 Alfa 25 26 PC 2018-09-22
2 1234 Alfa 25 NULL PC 2018-09-22
3 5678 Bravo 9 20 Console 2018-07-03
4 5678 Bravo 9 15 Console 2018-07-03
5 5678 Bravo 9 NULL Console 2018-07-03
6 9876 Charlie 84 100 Stamps 2018-06-14
7 9876 Charlie 84 90 Stamps 2018-06-14
8 9876 Charlie 84 85 Stamps 2018-06-14
9 9876 Charlie 84 NULL Stamps 2018-06-14
10 1470 Delta 98 100 Fashion 2018-06-15
11 1470 Delta 98 99 Fashion 2018-06-15
12 1470 Delta 98 NULL Fashion 2018-06-15
13 9631 Echo 56 65 Cars 2018-06-25
14 9631 Echo 56 NULL Cars 2018-06-25
15 7856 Foxtrot 98 NULL Dolls 2018-12-26
After looking around for answers I got a query for joining the VIEW on itself with only showing the highest bid instead of all bids:
SELECT VW.itemID, VW.title, VW.startPrice, VW.highestBid, VW.category, VW.endDate
FROM VW_SEARCH AS VW
INNER JOIN (SELECT itemID, MAX(highestBid) AS MaxBid
FROM VW_SEARCH
GROUP BY itemID) VJ
ON VW.itemID = VJ.itemID AND VW.highestBid = VJ.MaxBid
This gave the next results:
itemID title startPrice highestBid category endDate
1 1234 Alfa 25 26 PC 2018-09-22
2 5678 Bravo 9 20 Console 2018-07-03
3 9876 Charlie 84 85 Stamps 2018-06-14
4 1470 Delta 98 100 Fashion 2018-06-15
5 9631 Echo 56 65 Cars 2018-06-25
As I expected the result only showed the items with at least one bid on them. I tried added one extra condition on the subQuery and Joining RIGHT OUTER to make sure I would not get doubles of an itemID.
SELECT VW.itemID, VW.title, VW.startPrice, VW.highestBid, VW.category, VW.endDate
FROM VW_SEARCH AS VW
RIGHT OUTER JOIN (SELECT itemID, MAX(highestBid) AS MaxBid
FROM VW_SEARCH
WHERE highestBid > 0 OR highestBid IS NULL
GROUP BY itemID) VJ
ON VW.itemID = VJ.itemID AND VW.highestBid = VJ.MaxBid
This gave the following results (did not add result 5 - 1199 because it is all the same as result 4, this would happen in the actual table not the example table from above):
itemID title startPrice highestBid category endDate
1 1234 Alfa 25 26 PC 2018-09-22
2 5678 Bravo 9 20 Console 2018-07-03
3 9876 Charlie 84 85 Stamps 2018-06-14
4 NULL NULL NULL NULL NULL NULL
1200 1470 Delta 98 100 Fashion 2018-06-15
1201 9631 Echo 56 65 Cars 2018-06-25
While this is technicly allowing a NULL in the colums I need to get a result in the likes of :
itemID title startPrice highestBid catgory endDate
1 1234 Alfa 25 26 PC 2018-09-22
2 5678 Bravo 9 20 Console 2018-07-03
3 9876 Charlie 84 85 Stamps 2018-06-14
4 1470 Delta 98 100 Fashion 2018-06-15
5 9631 Echo 56 65 Cars 2018-06-25
6 7856 Foxtrot 98 NULL Dolls 2018-12-26
How do I get the desired result, or is it just impossible?
Also if the query could be written better, please say so.
Thanks in advance.
Solve the problem using a left join:
SELECT VW.itemID, VW.title, VW.startPrice, VW.highestBid, VW.category, VW.endDate
FROM VW_SEARCH VW LEFT JOIN
(SELECT itemID, MAX(highestBid) AS MaxBid
FROM VW_SEARCH
GROUP BY itemID
) VJ
ON VW.itemID = VJ.itemID AND VW.highestBid = VJ.MaxBid;
Or, use the ANSI-standard ROW_NUMBER() function:
select vw.*
from (select vw.*,
row_number() over (partition by itemID
order by highestBid nulls last
) as seqnum
from vw_search vw
) vw
where seqnum = 1;
This guarantees one row per item.
Note: Not all databases support NULLS LAST. This may not even be necessary, but you can also implement it using a case expression.
Can you give the definition of the view at least? Maybe the table definition too.
I would go only with subquery as because identity column :
select vw.*
from vw_search vw
where id = (select vm1.id
from vw_search vm1
where vm.itemID = vw1.itemID and vm1.highestBid is not null
order by vm1.highestBid desc
limit 1
);
However, some DBMS has not support LIMIT clause such as SQL Server if so, then you can use TOP clause instead.

How to use microsoft access or sql pivot

I would like to use microsoft access or query to change from table1
student name course_attended date quiz score
john course 1 3/1/2017 98
carl course 1 3/1/2017 90
george course 1 3/1/2017 77
john course 2 3/5/2017 99
carl course 2 3/5/2017 96
george course 2 3/5/2017 80
john course 3 4/4/2017 77
carl course 3 4/4/2017 80
george course 3 4/4/2017 85
to table2
student name course 1 course 2 course 3
john 3/1/2017 3/5/2017 4/4/2017
98 99 95
carl 3/1/2017 3/5/2017 4/4/2017
90 96 89
george 3/1/2017 3/5/2017 4/4/2017
77 80 85
Basically, with select distinct [student name] use transformation and pivot
to change from table1 to table2. Please help. I would be greatly appreciated it.
If you don't need to do any calcs on the output, try:
TRANSFORM First([attend_date] & Chr(13) & Chr(10) & [quiz_score]) AS Data
SELECT student_name
FROM Tablename
GROUP BY student_name
PIVOT course;
Date is a reserved word. Should not use reserved words as names. Also, avoid spaces and special characters/punctuation (underscore only exception) in names.
I tried this,
TRANSFORM First([date_a] & Chr(13) & Chr(10) & [quiz_score]) AS Data
SELECT student_name
FROM tbl_quiz
GROUP BY student_name
PIVOT course_attended;
and the query does not show the quiz_score. However, the form created from the query result shows it.
Thanks a lot.

Oracle select random rows from table based on criteria in another table (Stratified Sampling)

I have 2 tables. The first is the base table with the information in it and the 2nd table has the criteria I need random rows selected from Table 1 based on criteria in Table 2. Would prefer not doing this manually since the permutations for the criteria in my table is close to hundred. Need the code to get try get random stratified samples from my database.
Table_1
ID Fruit Subject
123 Apple Math
124 Apple Science
125 Apple History
126 Apple Math
127 Apple Science
128 Orange Math
129 Orange Science
130 Orange Science
131 Orange Science
132 Orange History
133 Orange Science
134 Pineapple History
135 Pineapple History
136 Pineapple History
137 Pineapple History
138 Pineapple Math
Table_2
Fruit Subject Count
Apple Math 1
Apple Science 2
Apple History 1
Orange Science 2
Orange History 1
Pineapple History 3
Pineapple Math 1
Output (Random Selection based on criteria in Table 2)
ID Fruit Subject
123 Apple Math
124 Apple Science
125 Apple History
127 Apple Science
128 Orange Math
129 Orange Science
130 Orange Science
132 Orange History
134 Pineapple History
135 Pineapple History
137 Pineapple History
138 Pineapple Math
It sounds like you can sort the rows using dbms_random and use the analytic function row_number to sort them within the partition
select id,
fruit,
subject
from(select t1.*,
t2.cnt,
row_number() over (partition by t1.fruit, t1.subject
order by dbms_random.value) rnk
from table_1 t1
join table_2 t2
on( t1.fruit = t2.fruit and
t1.subject = t2.subject ))
where rnk <= cnt