Suppose if I have table1 as following
Category Brand Value
A A1 4
B B1 7
C C1 8
A A2 3
B B2 4
C C2 6
A A3 9
B B3 10
C C3 1
A A4 5
Now if I want to calculate rank for each brand but grouped by category how do I go about it?
Something like
Select rank() (over value)
from table
group by category
Expected output is this:
Category Brand Value Rank
A A3 9 1
A A4 5 2
A A1 4 3
A A2 3 4
B B3 10 1
B B1 7 2
B B2 4 3
C C1 8 1
C C2 6 2
C C3 1 3
Maybe you are looking for something like this.
See this official documentation on DENSE_RANK for more details
select brand, category, dense_rank() over(partition by category order by value desc) as dr
from table
You may add a PARTITION BY clause to your RANK() call, specifying the category as the partition.
SELECT RANK() OVER (PARTITION BY category ORDER BY value) rnk
FROM yourTable
ORDER BY category, rnk;
Need help with Oracle query which will provide the output in below the format.
Sample table
c1 c2 c3 c4
-- -- -- --
A 1 A1
B 2 B1 C1
D 6 E2 A1
A 2 A1
C 3 C1
D 4 D1 E1
I want to join same table where data in 3rd Column matches the data in 4th and expecting the data to be sorted as subsequent records as below
c1 c2 c3 c4
-- -- -- --
A 1 A1
A 2 A1
D 6 E2 A1
B 2 B1 C1
C 3 C1
That's not a grouping, it's a sorting that you need:
select *
from your_table
order by coalesce(col1,'ZZZ') desc,
col2 desc --coalesce will use 'ZZZ' to order if column is null
I have a table (t1) with multiple rows of statuses for different references, one column being a ReferenceID and another column being a StatusID.
t1.ReferenceID - t1.StatusID
A1 - 1
A1 - 2
A1 - 3
A1 - 4
A2 - 1
A2 - 3
A3 - 1
A3 - 3
A4 - 1
A4 - 4
A5 - 2
A5 - 3
I have a second table (t2) which is the list of all available StatusID's
t2.StatusID
1
2
3
4
I need to be able to pull a list of ReferenceID's from t1 where StatusID '1' exists, however it is missing one or more of the other StatusID's in table 2.
i.e. using the above the following referenceID's would be returned:
A2
A3
A4
Don;t know if this will work on SQLAnywhere.
SELECT DISTINCT r.ReferenceID
FROM (SELECT ReferenceID FROM TableName WHERE StatusID = 1 GROUP BY ReferenceID) r
CROSS JOIN (SELECT StatusID FROM TableName GROUP BY StatusID) d
LEFT JOIN TableName a
ON d.StatusID = a.StatusID AND
r.ReferenceID = a.ReferenceID
WHERE a.StatusID IS NULL
ORDER BY r.ReferenceID
SQLFiddle Demo (running in MySQL)
Let me try to explain the scenario. I have two tables A (Columns - A1, A2, A3) & B (Columns - B1, B2, B3). I need to join table A with table B on A1.B2. For every join, table B has one or two records with different values for B3(X or Y). I wanna write one query where the JOIN query needs to pick the row with B3=X(if there's no other row with B3=Y); If two rows exists (B3=X & B3=Y), then the query needs to pick only the row with B3=Y (ignoring the row with B3=X).
Let me try to give some values to the tables & explain a little bit more.
Table A
********
A1 A2 A3
1 11 111
2 22 222
3 33 333
4 44 444
Table B
********
B1 B2 B3
6 1 X
7 1 Y
8 2 X
9 3 X
10 3 Y
11 4 X
Again.. JOIN is on A1.B2. The result should be as following,
JOIN Results
*************
A1 A2 A3 B1 B2 B3
1 11 111 7 1 Y
2 22 222 8 2 X
3 33 333 10 3 Y
4 44 444 11 4 X
Let me know if you guys have any clarification about my question.
Thanks in advance.
Yogi
You can pick the rows from table B with the ROW_NUMBER function if you partition by the join column and order by your "picking order" column:
SELECT b1, b2, b3,
ROW_NUMBER() OVER (PARTITION BY b2 ORDER BY b3 DESC) as rn
FROM b;
1 Y 1
1 X 2
2 X 1
3 Y 1
3 X 2
4 X 1
Then you can filter the first row, the one with rn=1:
SELECT b1, b2, b3
FROM (SELECT b1, b2, b3,
ROW_NUMBER() OVER (PARTITION BY b2 ORDER BY b3 DESC) as rn
FROM b)
WHERE rn=1;
7 1 Y
8 2 X
10 3 Y
11 4 X
The filtered rows can then be joined to table a:
SELECT *
FROM a
JOIN (
SELECT b1, b2, b3
FROM (SELECT b1, b2, b3,
ROW_NUMBER() OVER (PARTITION BY b2 ORDER BY b3 DESC) as rn
FROM b
)
WHERE rn=1
) bfilter ON a.a1 = bfilter.b2;
1 11 111 7 1 Y
2 22 222 8 2 X
3 33 333 10 3 Y
4 44 444 11 4 X
If 'X' and 'Y' are not actual values, you can extend the ORDER clause with a CASE statement to allow for general values:
ROW_NUMBER() OVER (PARTITION BY b2 ORDER BY
CASE b3 WHEN 'Y' THEN 1
WHEN 'X' THEN 2
...
END ASC)
Edit:
SELECT a1, a2, a3, b1, b2, b3
FROM (
SELECT a1, a2, a3, b1, b2, b3,
ROWNUMBER() OVER (PARTITION BY a1 ORDER BY
CASE WHEN a2=... AND b3=... THEN 1
WHEN a2=... AND b3=... THEN 2
...
END ASC)
FROM a JOIN b ON a.a1 = b.b2
)
WHERE rn = 1;
You can use left outer joins as follows
select A.A1, A.A2, A.A3,
nvl(BT1.B1, BT2.B1),
nvl(BT1.B2, BT2.B2),
nvl(BT1.B3, BT2.B3) from A
left outer join B BT1 on A.A1 = BT1.B2 and BT1.B3 = 'Y'
left outer join B BT2 on A.A1 = BT2.B2 and BT2.B3 = 'X'
A good explanation of the various joins is at http://www.codinghorror.com/blog/2007/10/a-visual-explanation-of-sql-joins.html
Here is, how I would do it:
Make the join
group by B2
take the max(B3)
That way you ensure that X is only picked, when there is no alphabetically higher value (Y) available
With UNION
select a.*,b.* from a,b
where a.a1=b.b2
and b.b3='Y'
union
select a.*,b.* from a,b
where a.a1=b.b2
and not exists (select bb.br from b bb where bb.b2=a.a1 and bb.b3='Y')
Without UNION
select a.*,b.* from a,b
where a.a1=b.b2
and (b.b3='Y'
or not exists (select bb.b3 from b bb where bb.b2=a.a1 and bb.b3='Y'))
The constraint here is that B has exactly 1 or 2 rows for each A's row
I have a table with 3 columns in which one is empty.
its like this,
c1 c2 c3
1 1000
1 1001
1 1004
2 1005
2 1007
3 1009
I want to insert values to c3 like
c1 c2 c3
1 1000 1
1 1001 2
1 1004 3
2 1005 1
2 1007 2
3 1009 1
Can anybody help?
The simplest solution is the one that pilcrow describes above: for each record R, c3 is equal to the number of records that have the same c1 as R, and a c2 that is less than or equal to that of R. As a SQL statement:
UPDATE table_name t
SET c3 =
( SELECT COUNT(1)
FROM table_name
WHERE c1 = t.c1
AND c2 <= t.c2
)
;
(Replace table_name with your table-name, of course.)
This might be faster than the nested sub-select (but you will need to test it)
merge into your_table u
using
(
select c1,
c2,
row_number() over (partition by c1 order by c2) as rn
from your_table
) t on (t.c1 = u.c1 and t.c2 = u.c2)
when matched then
update
set u.c3 = rn;