Sorting a group in datatable based on result in rows - sql

I am trying to do a group sorting on Datatables. As of now I am having data like:
+-------+-----+--------+
| rowno | mno | result |
+-------+-----+--------+
| 1 | 80 | 20 |
| 1 | 81 | 10 |
| 1 | 82 | 30 |
| 2 | 80 | 40 |
| 2 | 81 | 50 |
| 2 | 82 | 60 |
| 3 | 80 | 70 |
| 3 | 81 | 60 |
| 3 | 82 | 50 |
+-------+-----+--------+
As per the requirement , i will be selecting a particular mno, lets say 81 and then depending on the result for 81 i.e. 10, 50 and 60, I would like to sort entire group in descending order. Which means the result would be something like:
+-------+-----+--------+
| rowno | mno | result |
+-------+-----+--------+
| 3 | 80 | 70 |
| 3 | 81 | 60 |
| 3 | 82 | 50 |
| 2 | 80 | 40 |
| 2 | 81 | 50 |
| 2 | 82 | 60 |
| 1 | 80 | 20 |
| 1 | 81 | 10 |
| 1 | 82 | 30 |
+-------+-----+--------+
I am having the entire set as Datatable and am thinking of applying Linq to solve this one. Or if a SQL Query could be suggested that would also be fine.

Try this
SELECT rowno,mno,result from your_table
order by rowno desc

With LINQ to DataSet (dt is your DataTable):
var sorted = dt.AsEnumerable()
.OrderByDescending(r => r.Field<int>("rowno"))
.CopyToDataTable();
Without LINQ:
var view = dt.DefaultView;
view.Sort = "rowno DESC";
var sorted = view.ToTable();

Related

Select All rows WHERE ARRAY = "type"

I have a problem with a PostgreSQL query.
I have a table named "pokemons" with different columns :
id | name | pv | attaque | defense | attaque_spe | defense_spe | vitesse | type
-----+------------+-----+---------+---------+-------------+-------------+---------+------------------
1 | Bulbizarre | 45 | 49 | 49 | 65 | 65 | 45 | {Plante,Poison}
2 | Herbizarre | 60 | 62 | 63 | 80 | 80 | 60 | {Plante,Poison}
3 | Florizarre | 80 | 82 | 83 | 100 | 100 | 80 | {Plante,Poison}
4 | Salameche | 39 | 52 | 43 | 60 | 50 | 65 | {Feu}
5 | Reptincel | 58 | 64 | 58 | 80 | 65 | 80 | {Feu}
6 | Dracaufeu | 78 | 84 | 78 | 109 | 85 | 100 | {Feu,Vol}
7 | Carapuce | 44 | 48 | 65 | 50 | 64 | 43 | {Eau}
8 | Carabaffe | 59 | 63 | 80 | 65 | 80 | 58 | {Eau}
9 | Tortank | 79 | 83 | 100 | 85 | 105 | 78 | {Eau}
In this table, I want to select all the rows with a specific type.
Kind of things, I did try :
SELECT * FROM pokemons WHERE 'feu'=ANY(type);
I tried many things with ALL or stuff like that but can't get a single a row.
Can you help me there please.
Thanks.
Adding to the solution mentioned in the comment, you may also make a case insensitive comparison like this.
SELECT * FROM pokemons WHERE 'feu' ilike ANY(type);

Oracle SQL: getting all row maximum number from specific multiple criteria

I have the following table named foo:
ID | D1 | D2 | D3 |
---------------------
1 | 47 | 3 | 71 |
2 | 47 | 98 | 82 |
3 | 0 | 99 | 3 |
4 | 3 | 100 | 6 |
5 | 48 | 10 | 3 |
6 | 49 | 12 | 4 |
I want to run a select query and have the results show like this
ID | D1 | D2 | D3 | Result |
------------------------------
1 | 47 | 3 | 71 | D3 |
2 | 47 | 98 | 82 | D2 |
3 | 0 | 99 | 3 | D2 |
4 | 3 | 100 | 6 | D2 |
5 | 48 | 10 | 3 | D1 |
6 | 49 | 12 | 4 | D1 |
So, basically I want to get Maximum value between D1, D2, D3 column divided by id.
As You may seen , ID 1 have D3 in the Result column since Maximum value between
D1 : D2 : D3
That Means 4 : 3 : 71 , Max value is 71. Thats Why The Result show 'D3'
Is there a way to do this in a sql query ?
Thanks!
For Oracle please try this one
select foo.*, case when greatest(d1, d2, d3) = d1 then 'D1'
when greatest(d1, d2, d3) = d2 then 'D2'
when greatest(d1, d2, d3) = d3 then 'D3'
end result
from foo
Consider the following - a normalized approach...
DROP TABLE IF EXISTS my_table;
CREATE TABLE my_table
(id INT NOT NULL
,d INT NOT NULL
,val INT NOT NULL
,PRIMARY KEY(id,d)
);
INSERT INTO my_table VALUES
(1,1,47),
(2,1,47),
(3,1,0),
(4,1,3),
(5,1,48),
(6,1,49),
(1,2,3),
(2,2,98),
(3,2,99),
(4,2,100),
(5,2,10),
(6,2,12),
(1,3,71),
(2,3,82),
(3,3,3),
(4,3,6),
(5,3,3),
(6,3,4);
SELECT * FROM my_table;
+----+---+-----+
| id | d | val |
+----+---+-----+
| 1 | 1 | 47 |
| 1 | 2 | 3 |
| 1 | 3 | 71 |
| 2 | 1 | 47 |
| 2 | 2 | 98 |
| 2 | 3 | 82 |
| 3 | 1 | 0 |
| 3 | 2 | 99 |
| 3 | 3 | 3 |
| 4 | 1 | 3 |
| 4 | 2 | 100 |
| 4 | 3 | 6 |
| 5 | 1 | 48 |
| 5 | 2 | 10 |
| 5 | 3 | 3 |
| 6 | 1 | 49 |
| 6 | 2 | 12 |
| 6 | 3 | 4 |
+----+---+-----+
SELECT x.*
FROM my_table x
JOIN
( SELECT id,MAX(val) max_val FROM my_table GROUP BY id) y
ON y.id = x.id
AND y.max_val = x.val;
+----+---+-----+
| id | d | val |
+----+---+-----+
| 1 | 3 | 71 |
| 2 | 2 | 98 |
| 3 | 2 | 99 |
| 4 | 2 | 100 |
| 5 | 1 | 48 |
| 6 | 1 | 49 |
+----+---+-----+
(This is intended as a MySQL solution - I'm not familiar with ORACLE syntax, so apologies if this doesn't port)
Does this answer your comment?
SELECT x.* , y.max_val
FROM my_table x
JOIN
( SELECT id,MAX(val) max_val FROM my_table GROUP BY id) y
ON y.id = x.id ;
+----+---+-----+---------+
| id | d | val | max_val |
+----+---+-----+---------+
| 1 | 1 | 47 | 71 |
| 1 | 2 | 3 | 71 |
| 1 | 3 | 71 | 71 |
| 2 | 1 | 47 | 98 |
| 2 | 2 | 98 | 98 |
| 2 | 3 | 82 | 98 |
| 3 | 1 | 0 | 99 |
| 3 | 2 | 99 | 99 |
| 3 | 3 | 3 | 99 |
| 4 | 1 | 3 | 100 |
| 4 | 2 | 100 | 100 |
| 4 | 3 | 6 | 100 |
| 5 | 1 | 48 | 48 |
| 5 | 2 | 10 | 48 |
| 5 | 3 | 3 | 48 |
| 6 | 1 | 49 | 49 |
| 6 | 2 | 12 | 49 |
| 6 | 3 | 4 | 49 |
+----+---+-----+---------+

How to generate merit list from exam results in SQL Server

I'm using SQL Server 2008 R2. I have a table called tstResult in my database.
AI SubID StudID StudName TotalMarks ObtainedMarks
--------------------------------------------------------
1 | 1 | 1 | Jakir | 100 | 90
2 | 1 | 2 | Rubel | 100 | 75
3 | 1 | 3 | Ruhul | 100 | 82
4 | 1 | 4 | Beauty | 100 | 82
5 | 1 | 5 | Bulbul | 100 | 96
6 | 1 | 6 | Ripon | 100 | 82
7 | 1 | 7 | Aador | 100 | 76
8 | 1 | 8 | Jibon | 100 | 80
9 | 1 | 9 | Rahaat | 100 | 82
Now I want a SELECT query that generate a merit list according to the Obtained Marks. In this query obtained marks "96" will be the top in the merit list and all the "82" marks will be placed one after another in the merit list. Something like this:
StudID StudName TotalMarks ObtainedMarks Merit List
----------------------------------------------------------
| 5 | Bulbul | 100 | 96 | 1
| 1 | Jakir | 100 | 90 | 2
| 9 | Rahaat | 100 | 82 | 3
| 3 | Ruhul | 100 | 82 | 3
| 4 | Beauty | 100 | 82 | 3
| 6 | Ripon | 100 | 82 | 3
| 8 | Jibon | 100 | 80 | 4
| 7 | Aador | 100 | 76 | 5
| 2 | Rubel | 100 | 75 | 6
;with cte as
(
select *, dense_rank() over (order by ObtainedMarks desc) as Merit_List
from tstResult
)
select * from cte order by Merit_List desc
you need to use Dense_rank()
select columns from tstResult order by ObtainedMarks desc

SQL Joining 2 Tables

I would like to merge two tables into one and also add a counter next to that. What i have now is
SELECT [CUCY_DATA].*, [DIM].[Col1], [DIM].[Col2],
(SELECT COUNT([Cut Counter]) FROM [MSD]
WHERE [CUCY_DATA].[Cut Counter] = [MSD].[Cut Counter]
) AS [Nr Of Errors]
FROM [CUCY_DATA] FULL JOIN [DIM]
ON [CUCY_DATA].[Cut Counter] = [DIM].[Cut Counter]
This way the data is inserted but where the values don't match nulls are inserted. I want for instance this
Table CUCY_DATA
|_Cut Counter_|_Data1_|_Data2_|
| 1 | 12 | 24 |
| 2 | 13 | 26 |
| 3 | 10 | 20 |
| 4 | 11 | 22 |
Table DIM
|_Cut Counter_|_Col1_|_Col2_|
| 1 | 25 | 40 |
| 3 | 50 | 45 |
And they need to be merged into:
|_Cut Counter_|_Data1_|_Data2_|_Col1_|_Col2_|
| 1 | 12 | 24 | 25 | 40 |
| 2 | 13 | 26 | 25 | 40 |
| 3 | 10 | 20 | 50 | 45 |
| 4 | 11 | 22 | 50 | 45 |
SO THIS IS WRONG:
|_Cut Counter_|_Data1_|_Data2_|_Col1__|_Col2__|
| 1 | 12 | 24 | 25 | 40 |
| 2 | 13 | 26 | NULL | NULL |
| 3 | 10 | 20 | 50 | 45 |
| 4 | 11 | 22 | NULL | NULL |
Kind regards, Bob
How are you getting the col1 and col2 values where there is no corresponding row in your DIM table? (Rows 2 and 4). Your "wrong" result is exactly correct, that's what the outer join does.

Adding rows and changing the row name

I have fetched the values from the sql server database from the following code,
SELECT [Zone Name]
,[Zone Count]
,[Phase Name]
FROM [Interface].[dbo].[VwZoneCount]
where [Zone Name] IN ('EB2GFNMZ','EB2GFSMZ','EB2GFNZ1','EB2GFSZ1','EB21FNZ1','EB21FSMZ','EB2IFSZ1','EB22FNZ1','EB22FSZ1','EB22FSMZ','EB23FNMZ','EB23FNZ1','EB23FNZ2','EB23FNZ3','EB23FSMZ','EB23FSZ1','EB23FSZ2','EB24FNMZ','EB24FNZ1','EB24FSMZ','EB24FSZ1','EB25FNMZ','EB25FNZ1','EB25FSMZ','EB25FSZ1','EB26FNMZ','EB26FNZ1','EB26FSMZ','EB26FSZ1','EB27FNZ1','EB27FSMZ')
GO
The ouput for the above query is ,
Zone Name Zone Count
EB24FNZ1 160
EB24FSMZ 10
EB24FSZ1 87
EB25FNMZ 82
EB25FNZ1 82
EB25FSMZ 12
EB25FSZ1 123
EB26FNMZ 4
EB26FNZ1 92
EB26FSMZ 23
EB26FSZ1 91
EB27FNZ1 1
EB27FSMZ 64
EB2GFNMZ 12
EB2GFNZ1 152
EB2GFSMZ 36
EB2GFSZ1 212
but i need the output by summing some row values .I need to combine values that have 'EB2GFN%' to one with different name,'EB21FN%'..similarly need to combine other rows. Can any body suggest me how i would do that .
Desired output:-
Zone Name Zone Count
EB24F_NORTH_WING 160
EB24F_SOUTH_WING 10+87
EB25F_NORTH_WING 82+82
EB25F_SOUTH_WING 12+123
EB26F_NORTH_WING 4+92
EB26F_SOUTH_WING 23+91
EB27F_NORTH_WING 1
EB27F_SOUTH_WING 64
EB2GF_NORTH_WING 12+152
EB2GF_SOUTH_WING 36+212
You can do this:
;WITH AllZones
AS
(
SELECT * FROM YourQuery
), WithGroupedZones
AS
(
SELECT
ZoneName,
ZoneCount,
LEFT(ZoneName, 2) Eb,
SUBSTRING(ZoneName, 3, 1) EbNumber,
SUBSTRING(ZoneName, 4, 3) F,
SUBSTRING(ZoneName, 8, 1) FNumber
FROM AllZones
)
SELECT
ZoneName,
(SELECT SUM(t2.ZoneCount)
FROM WithGroupedZones t2
WHERE t1.Eb = t2.Eb
AND t1.F = t2.F
AND t1.EBNumber= t2.EBnumber
) ZonesCount
FROM WithGroupedZones t1;
SQL Fiddle Demo
This will give you:
| ZONENAME | ZONESCOUNT |
-------------------------
| EB24FNZ1 | 160 |
| EB24FSMZ | 97 |
| EB24FSZ1 | 97 |
| EB25FNMZ | 164 |
| EB25FNZ1 | 164 |
| EB25FSMZ | 135 |
| EB25FSZ1 | 135 |
| EB26FNMZ | 96 |
| EB26FNZ1 | 96 |
| EB26FSMZ | 114 |
| EB26FSZ1 | 114 |
| EB27FNZ1 | 1 |
| EB27FSMZ | 64 |
| EB2GFNMZ | 164 |
| EB2GFNZ1 | 164 |
| EB2GFSMZ | 248 |
| EB2GFSZ1 | 248 |
Note that: This might be not the same result set that you are looking for. But you can modify the condition, I used in my query:
t1.Eb = t2.Eb
AND t1.F = t2.F
AND t1.EBNumber= t2.EBnumber
To get your desired output. Also note that the zones' names are grouped into:
| ZONENAME | ZONECOUNT | EB | EBNUMBER | F | FNUMBER |
--------------------------------------------------------
| EB24FNZ1 | 160 | EB | 2 | 4FN | 1 |
| EB24FSMZ | 10 | EB | 2 | 4FS | Z |
| EB24FSZ1 | 87 | EB | 2 | 4FS | 1 |
| EB25FNMZ | 82 | EB | 2 | 5FN | Z |
| EB25FNZ1 | 82 | EB | 2 | 5FN | 1 |
| EB25FSMZ | 12 | EB | 2 | 5FS | Z |
| EB25FSZ1 | 123 | EB | 2 | 5FS | 1 |
| EB26FNMZ | 4 | EB | 2 | 6FN | Z |
| EB26FNZ1 | 92 | EB | 2 | 6FN | 1 |
| EB26FSMZ | 23 | EB | 2 | 6FS | Z |
| EB26FSZ1 | 91 | EB | 2 | 6FS | 1 |
| EB27FNZ1 | 1 | EB | 2 | 7FN | 1 |
| EB27FSMZ | 64 | EB | 2 | 7FS | Z |
| EB2GFNMZ | 12 | EB | 2 | GFN | Z |
| EB2GFNZ1 | 152 | EB | 2 | GFN | 1 |
| EB2GFSMZ | 36 | EB | 2 | GFS | Z |
| EB2GFSZ1 | 212 | EB | 2 | GFS | 1 |
Then you can compare the ZoneName using these groups EB, EBNUMBER, F, FNUMBER
Try this, it will give you sums for groups that have first 6 letters in common:
SELECT LEFT(Zone_Prefix, 5) + CASE WHEN RIGHT(Zone_Prefix, 1) = 'N' THEN '_NORTH_WING' ELSE '_SOUTH_WING' END AS [Zone Name],
Cnt AS [Zone Count]
FROM
(
SELECT LEFT([Zone Name], 6) AS Zone_Prefix
,SUM([Zone Count]) Cnt
FROM [Interface].[dbo].[VwZoneCount]
WHERE [Zone Name] IN ('EB2GFNMZ','EB2GFSMZ','EB2GFNZ1','EB2GFSZ1','EB21FNZ1','EB21FSMZ','EB2IFSZ1','EB22FNZ1','EB22FSZ1','EB22FSMZ','EB23FNMZ','EB23FNZ1','EB23FNZ2','EB23FNZ3','EB23FSMZ','EB23FSZ1','EB23FSZ2','EB24FNMZ','EB24FNZ1','EB24FSMZ','EB24FSZ1','EB25FNMZ','EB25FNZ1','EB25FSMZ','EB25FSZ1','EB26FNMZ','EB26FNZ1','EB26FSMZ','EB26FSZ1','EB27FNZ1','EB27FSMZ')
GROUP BY
LEFT([Zone Name], 6)
) tbl
Here is an SQL Fiddle