3 level nested sorting - sql

I'm trying to implement a 3 level nested sort. Basically I have four columns:
A | B | C | D
--- | --- | --- | ---
bob | GOOD| 1 |
kat | BAD | | 24
bob | OK | | 15
bob | GOOD| 20 |
bob | OK | | 10
bob | OK | 5 |
I have three levels of sorting needed...first level Column A ASC, 2nd level is case sorting on column B, and the third level I need to sort based on values from C & D if B = 'GOOD' and sort based on C if B is any other value.
What I currently have is:
ORDER
BY A,
CASE
WHEN B ='GOOD' THEN 1
WHEN B = 'OK' THEN 2
WHEN B = 'BAD' THEN 3
END, C
However this only sorts the third level based on values of C.

You could use another case statement:
ORDER BY A,
CASE B WHEN 'GOOD' THEN 1
WHEN 'OK' THEN 2
WHEN 'BAD' THEN 3
END,
CASE B WHEN 'GOOD' THEN C ELSE D END
In the sample data no row ever seems to have values for both C and D. If this is really the case, you could simplify things using coalesce:
ORDER BY A,
CASE B WHEN 'GOOD' THEN 1
WHEN 'OK' THEN 2
WHEN 'BAD' THEN 3
END,
COALESCE(C, D)

If i got it right
ORDER BY A,
CASE
WHEN B ='GOOD' THEN 1
WHEN B = 'OK' THEN 2
WHEN B = 'BAD' THEN 3
END, C,
CASE WHEN B ='GOOD' THEN D END

Related

Replace NULL with the values

We have a requirement as shown below.
There are 6 item_class - A,B,C,D,A1A,A1B which should appear for all the records.
Record:
Item_class Rev_id
A 1
B 1
C 2
D 1
Null 1
Null 2
We need to display the record as given below table,
item_class Rev_id
A 1
B 1
C 2
D 1
A1A 1
A1B 2
So all the item_class(A,B,C,D,A1A,A1B) should display when item class is null and also it checks if item_clas A,B,C are already present then for different rev_id it will display the remaining one (i.e. D,A1A,A1B) but all item_class should covered.
How can we write a query to fetch similar records?
the issue got resolved by using outer join. Please find below,
select b.item_class,
a.rev_id
from cct_test a
right outer join cct_item_details b
on a.item_class = b.item_class and a.rev_id = 1;
Output:
item_class | rev_id
A | 1
C | 1
A1B | null
A1A | null
D | null
B | null

Group by 3 columns: "Each group by expression must contain at least one column that is not an outer reference"

I know questions regarding this error message have been asked already, but I couldn't find any that really fit my problem.
I have a table with three columns (A,B,C) containing different values and I need to identify all the identical combination. For example out of "TABLE A" below:
| A | B | C |
| 1 | 2 | 3 |
| 1 | 3 | 3 |
| 1 | 2 | 3 |
| 2 | 2 | 2 |
| 1 | 3 | 3 |
... I would like too get "TABLE B" below:
| A | B | C | count |
| 1 | 2 | 3 | 1 |
| 1 | 3 | 3 | 1 |
| 2 | 2 | 2 | 1 |
(I need the last column "count" with 1 in each row for later usage)
When I try with "group by A,B,C" I get the error mentioned in the title. Any help would be greatly appreciated!
FYI, I don't think it really changes the matter, but "TABLE A" is obtained from an other table: "SOURCE_TABLE", thanks to a query of the type:
select (case when ... ),(case when ...),(case when ...) from SOURCE_TABLE
and I need to build "TABLE B" with only one query.
i think what you are after of is using distinct
select distinct A,B,C, 1 [count] -- where 1 is a static value for later use
from (select ... from sourcetable) X
Sounds like you have the right idea. My guess is that the error is occurring due to an outer reference in your CASE statements. If you wrapped your first query in another query, it may alleviate this issue. Try:
SELECT A, B, C, COUNT(*) AS [UniqueRowCount]
FROM (
SELECT (case when ... ) AS A, (case when ...) AS B, (case when ...) AS C FROM SOURCE_TABLE
) AS Subquery
GROUP BY A, B, C
After re-reading your question, it seems that you're not counting at all, just putting a "1" after each distinct row. If that's the case, then you can try:
SELECT DISTINCT A, B, C, [Count]
FROM (
SELECT (case when ... ) AS A, (case when ...) AS B, (case when ...) AS C, 1 AS [Count] FROM SOURCE_TABLE
) AS Subquery
Assuming your outer reference exceptions were occurring in only your aggregations, you should also simply try:
SELECT DISTINCT (case when ... ) AS A, (case when ...) AS B, (case when ...) AS C, 1 AS [Count] FROM SOURCE_TABLE

subquery to derive a value if all values of the column is the same for

Hi i have a situation here with Oracle SQL to come out with the sql result as the following :-
Company No of Employees Group Derived Field
a 1 x
b 1 x
c 2 y
d 1 y
so based on the group if all the company has same no of employees then i want the derived field to be
true else false.
So for group x , if company a and b has the same no of employees then derived field for
a and b would be true. As for c and d because the no of employees is different so the derived field
should be false.
any help would be appreciated. thanks
You want to use an analytic function. I think this is what you want:
select t.*,
(case when min(NumEmployees) over (partition by grp) =
max(NumEmployees) over (partition by grp)
then 1
else 0
end) as DerivedField
from table t;
Note: I usually represent booleans as 0 and 1.
Here is a purely sql solution. Assume the column names are company,number,ggroup,test.
for convenience create a view of table t as
create view gnums as select count(distinct number)as gnum,count(number) as num, ggroup from t group by ggroup;
The this select
select a.*,b.gnum = 1 and b.num <> 1 as test from t a,gnums b where a.ggroup = b.ggroup;
yields
id | company | number | ggroup | test
----+---------+--------+--------+------
1 | a | 1 | x | t
2 | b | 1 | x | t
3 | c | 2 | y | f
4 | d | 1 | y | f
5 | e | 2 | z | f
I added row e to show that any group with only one company should yield false, assuming that's what you intended.

Removing "duplicate" groups in SQL

I'm trying to get rid of duplicate groups in SQL, but the problem is they're not really duplicates.
I have a table like this:
a | b
0 | 1
2 | 3
however, the table also adds B, A back into it so I end up with this as the final table:
a | b
0 | 1
2 | 3
--------
1 | 0
3 | 2
What I'm trying to do is return the distinct pairs (the first table), and I'm having issues with it. Any hints would be much appreciated!
Try this:
select distinct (case when a < b then a else b end) as First,
(case when a < b then b else a end) as Second
from t
If you are using Oracle (which is the assumption with SQLPlus), you can simplify this to:
select distinct least(a, b), greatest(a, b)
from t

Return count(*) even if 0

I have the following query:
select bb.Name, COUNT(*) as Num from BOutcome bo
JOIN BOffers bb ON bo.ID = bb.BOutcomeID
WHERE bo.EventID = 123 AND bo.OfferTypeID = 321 AND bb.NumA > bb.NumB
GROUP BY bb.Name
The table looks like:
Name | Num A | Num B
A | 10 | 3
B | 2 | 3
C | 10 | 3
A | 9 | 3
B | 2 | 3
C | 9 | 3
The expected output should be:
Name | Count
A | 2
B | 0
C | 2
Because when name is A and C then Num A is bigger to times than Num B and when Name is B, in both records Num A is lower than Num B.
My current output is:
Name | Count
A | 2
C | 2
Because B's output is 0, i am not getting it back in my query.
What is wrong with my query? how should I get it back?
Here is my guess. I think this is a much simpler approach than all of the left/right join hoops people have been spinning their wheels on. Since the output of the query relies only on columns in the left table, there is no need for an explicit join at all:
SELECT
bb.Name,
[Count] = SUM(CASE WHEN bb.NumA > bb.NumB THEN 1 ELSE 0 END)
-- just FYI, the above could also be written as:
-- [Count] = COUNT(CASE WHEN bb.NumA > bb.NumB THEN 1 END)
FROM dbo.BOffers AS bb
WHERE EXISTS
(
SELECT 1 FROM dbo.BOutcome
WHERE ID = bb.BOutcomeID
AND EventID = 123
AND OfferTypeID = 321
)
GROUP BY bb.Name;
Of course, we're not really sure that both Name and NumA/NumB are in the left table, since the OP talks about two tables but only shows one table in the sample data. My guess is based on the query he says is "working" but missing rows because of the explicit join.
Another wild guess. Feel free to downvote:
SELECT ba.Name, COUNT(bb.BOutcomeID) as Num
FROM
( SELECT DISTINCT ba.Name
FROM
BOutcome AS b
JOIN
BOffers AS ba
ON ba.BOutcomeID = b.ID
WHERE b.EventID = 123
AND b.OfferTypeID = 321
) AS ba
LEFT JOIN
BOffers AS bb
ON AND bb.Name = ba.Name
AND bb.NumA > bb.NumB
GROUP BY ba.Name ;