SELECT statement with multiple WHERE criteria (MS-Access) - sql

Below is the sample data:
c1 c2 c3 c4 c5
1 a1 a 1 1
2 a2 a 2 1
3 a3 a 3 1
4 a4 a 4 1
5 b1 b 1 1
6 b2 b 2 1
7 b3 b 3 1
8 b4 b 4 1
9 a1 c 3 1
I want to get the the below details:
c1 c2 c3 c4 c5
1 a1 a 1 1
5 b1 b 1 1
9 a1 c 3 1
C1 is primary key, the criteria is for any given unique(c2) where c4 is the lowest, I want to return the contents(all the 5 columns) of the row.

Try this:
SELECT t1.*
FROM Table1 t1
INNER JOIN
(
SELECT c3, MIN(c4) c4
FROM Table1
GROUP BY c3
) t2 ON t1.c3 = t2.c3 ANd t1.c4 = t2.c4
SQL Fiddle Demo
Update:1 In SQL the returned results is a set set(unless you specify an ORDER BY clause, it is a cursor in this case), wherein the order is not guaranteed. This is a standard. You should use an ORDER BY clause if you want to guarantee a specific order. In your case , the results is not guaranteed to be ordered like 1 5 9. Add ORDER BY c1 instead.
The ORDER BY clause might be crucial in some cases, for example, if want to get the top three rows, or the maximum one, in this case you have to specify an ORDER BY clause.
So if you wants to persist a specific order the you have specify an ORDER BY.
1 As noted by #Fahim Parker, see the comments below.

select c1,c2,c3,c4,c5
from table
where c4= (select min(c4) from table as f where f.c4 = table.c4);
i hope that helps

Related

How to calculate rank with group by in sql?

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;

How to order the records from different records with matching data in two differents columns as continous rows in output

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

SQL Search for records with missing values in the same table

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)

ORACLE Special JOIN

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

sql script to create generate consecutive numbers depending on a column and again start with 1

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;