Count distinct values of a Column based on Distinct values of First Column - sql

I am dealing with a huge volume of traffic data. I want to identify the vehicles which have changed their lanes, I'm Microsoft Access with VB.Net.
Traffic Data:
Vehicle_ID Lane_ID Frame_ID Distance
1 2 12 100
1 2 13 103
1 2 14 105
2 1 16 130
2 1 17 135
2 2 18 136
3 1 19 140
3 2 20 141
I have tried to distinct the Vehicle_ID and then count(distinct Lane_ID).
I could list the distinct Vehicle_ID but the it counts the total Lane_ID instead of Distinct Lane_ID.
SELECT
Distinct Vehicle_ID, count(Lane_ID)
FROM Table1
GROUP BY Vehicle_ID
Shown Result:
Vehicle_ID Lane Count
1 3
2 3
3 2
Correct Result:
Vehicle_ID Lane Count
1 1
2 2
3 2
Further to that i would like to get all Vehicle_ID who have changed their lane (all data including previous lane and new lane). Output result would be somehow like: Vehicle_ID Lane_ID Frame_ID Distance
2 1 17 135
2 2 18 136
3 1 19 140
3 2 20 141

Access does not support COUNT(DISTINCT columnname) so do this:
SELECT t.Vehicle_ID, COUNT(t.Lane_ID) AS [Lane Count]
FROM (
SELECT DISTINCT Vehicle_ID, Lane_ID FROM Table1
) AS t
GROUP BY t.Vehicle_ID
So
to identify the vehicles which have changed their lanes
you need to add to the above query:
HAVING COUNT(t.Lane_ID) > 1

SELECT
Table1.Vehicle_ID,
LANE_COUNT
FROM Table1
JOIN (
SELECT Vehicle_ID, COUNT(*) as LANE_COUNT FROM (
SELECT distinct Vehicle_ID, Lane_ID FROM Table1
) dTable1 # distinct vehicle and land id
GROUP BY Vehicle_ID # counting the distinct
) cTable1 ON cTable1.Vehicle_ID = Table1.Vehicle_ID # join the table with the counting
I think you should do one by one,
Distinct the vehicle id and land id
counting the distinct combination
and merge the result with the actual table.

If you want vehicles that have changed their lanes, then you can do:
SELECT Vehicle_ID,
IIF(MIN(Lane_ID) = MAX(Lane_ID), 0, 1) as change_lane_flag
FROM Table1
GROUP BY Vehicle_ID;
I think this is as good as counting the number of distinct lanes, because you are not counting actual "lane changes". So this would return "2" even though the vehicle changes lanes multiple times:
2 1 16 130
2 1 17 135
2 2 18 136
2 1 16 140
2 1 17 145
2 2 18 146

Related

SUM a column in SQL, based on DISTINCT values in another column, GROUP BY a third column

I'd appreciate some help on the following SQL problem:
I have a table of 3 columns:
ID Group Value
1 1 5
1 1 5
1 2 10
1 2 10
1 3 20
2 1 5
2 1 5
2 1 5
2 2 10
2 2 10
3 1 5
3 2 10
3 2 10
3 2 10
3 4 50
I need to group by ID, and I would like to SUM the values based on DISTINCT values in Group. So the value for a group is only accounted for once even though it may appear multiple for times for a particular ID.
So for IDs 1, 2 and 3, it should return 35, 15 and 65, respectively.
ID SUM
1 35
2 15
3 65
Note that each Group doesn't necessarily have a unique value
Thanks
the CTE will remove all duplicates, so if there a sdiffrenet values for ID and Group, it will be counted.
The next SELECT wil "GROUP By" ID
For Pstgres you would get
WITH CTE as
(SELECT DISTINCT "ID", "Group", "Value" FROM tablA
)
SELECT "ID", SUM("Value") FROM CTE GROUP BY "ID"
ORDER BY "ID"
ID | sum
-: | --:
1 | 35
2 | 15
3 | 65
db<>fiddle here
Given what we know at the moment this is what I'm thinking...
The CTE/Inline view eliminate duplicates before the sum occurs.
WITH CTE AS (SELECT DISTINCT ID, Group, Value FROM TableName)
SELECT ID, Sum(Value)
FROM CTE
GROUP BY ID
or
SELECT ID, Sum(Value)
FROM (SELECT DISTINCT * FROM TableName) CTE
GROUP BY ID

How to select distinct values for two and return all columns?

I want to select distinct values from two columns.
Example data:
ID TITLE SOURCE TARGET
1 asd 12 2
2 asd1 123 125
3 asd1 123 56
4 asd2 123 125
5 asd3 164 146
I want to get distinct data for source and target columns ID - 2 and ID - 4 are duplicates.
ID TITLE SOURCE TARGET
1 asd 12 2
2 asd1 123 125
3 asd1 123 56
5 asd3 164 146
If you just want the distinct values, use select distinct:
select distinct source, target
from example t;
If you want the rows where the source/target only appears on one row, then one method uses window functions:
select t.*
from (select t.*,
count(*) over (partition by source, target) as cnt
from example t
) t
where cnt = 1;

sql for Access Database

I am dealing with a huge volume of traffic data. I want to identify the vehicles which have changed their lanes in MS Access database. I want to identify those records only which has changed the lane (immediate two records: before lane change and after lane change)
Traffic Data:
Vehicle_ID Lane_ID Frame_ID Distance
1 2 12 100
1 2 13 103
1 2 14 105
2 1 15 107
***2 1 16 130
2 2 17 135***
2 2 18 136
***3 1 19 140
3 2 20 141***
3 2 21 147
4 2 22 149
***4 2 23 151
4 1 24 154***
4 1 25 159
With assistance from here i have sorted out those Vehicle_ID which have changed their lanes:
SELECT t.Vehicle_ID, COUNT(t.Lane_ID) AS [Lane Count]
FROM (
SELECT DISTINCT Vehicle_ID, Lane_ID FROM Table1
) AS t
GROUP BY t.Vehicle_ID
HAVING COUNT(t.Lane_ID) > 1
Shown Result:
Vehicle_ID Lane Count
2 2
3 2
4 2
Now i want to do further analysis withe records of lane changing by segregating immediate two records: before and after lane change. My desired output would be:
Desired Result:
Vehicle_ID Lane_ID Frame_ID Distance
***2 1 16 130
2 2 17 135***
***3 1 19 140
3 2 20 141***
***4 2 23 151
4 1 24 154***
Assuming the frame ids have no gaps, you can do this using joins:
select t1.*
from (table1 as t1 inner join
table1 as t1prev
on t1prev.Vehicle_ID = t1.Vehicle_ID and
t1prev.frame_id = t1.frame_id - 1
) inner join
table1 as t1next
on t1next.Vehicle_ID = t1.Vehicle_ID and
t1next.frame_id = t1.frame_id + 1
where t1prev.lane_id <> t1.lane_id or
t1next.lane_id <> t1.lane_id;
Otherwise, this will be a very expensive query.
You can do it with EXISTS:
select t.* from Table1 t
where
exists (
select 1 from Table1
where
vehicle_id = t.vehicle_id
and
frame_id in (t.frame_id - 1, t.frame_id + 1)
and
lane_id <> t.lane_id
)

SELECT clause with SUM condition

Have this table :
//TEST
NUMBER TOTAL
----------------------------
1 158
2 355
3 455
//TEST1
NUMBER QUANTITY UNITPRICE
--------------------------------------------
1 3 5
1 3 6
1 3 4
2 4 8
3 5 4
I used following query:
SELECT t.NUMBER,sum(t.TOTAL),NVL(SUM(t2.quantity*t2.unitprice),0)
FROM test t INNER JOIN test1 t2 ON t.NUMBER=t2.NUMBER
GROUP BY t.NUMBER;
OUTPUT:
NUMBER SUM(TOTAL) SUM(t2.quantity*t2.unitprice)
-----------------------------------------------------------
1 474 45 <--- only this wrong
2 355 32
It seem like loop for three times so 158*3 in the record.
EXPECTED OUTPUT:
NUMBER SUM(TOTAL) SUM(t2.quantity*t2.unitprice)
-----------------------------------------------------------
1 158 45
2 355 32
You have to understand that the result of your join is something like this:
//TEST1
NUMBER QUANTITY UNITPRICE TOTAL
--------------------------------------------------------------
1 3 5 158
1 3 6 158
1 3 4 158
2 4 8 355
3 5 4 455
It means you don't need to apply a SUM on TOTAL
SELECT t.NUMBER,t.TOTAL,NVL(SUM(t2.quantity*t2.unitprice),0)
FROM test t INNER JOIN test1 t2 ON t.NUMBER=t2.NUMBER
GROUP BY t.NUMBER, t.TOTAL;
Something like this should work using a subquery separating the sums:
select t.num,
sum(t.total),
test1sum
from test t
join (
select num, sum(qty*unitprice) test1sum
from test1
group by num
) t2 on t.num = t2.num
group by t.num, test1sum
SQL Fiddle Demo
In regards to your sample data, you may not even need the additional group by on the test total field. If that table only contains distinct ids, then this would work the same:
select t.num,
t.total,
sum(qty*unitprice)
from test t
join test1 t2 on t.num = t2.num
group by t.num, t.total

Simple data, Complex query on SQL Server

I need to make a query over an SQL Server table but I don't know exactly how.
Consider this table (the real table is much more complex, Ord1 and Ord2 are dates that could be null, but i simplified it to this case):
Data of MyTable
ID MaqID Ord1 Ord2
------------------------
1 144 4 3
2 144 2 1
3 12 2 3
4 144 3 5
5 12 3 1
6 144 4 2
7 12 2 4
8 144 2 3
9 12 1 5
10 12 3 2
I need records for specific MaqID in Specific Order. I get that with this Query:
SELECT * FROM myTable WHERE MaqID=144 ORDER BY MaqID, Order1 DESC, Order2
Wich give me:
ID MaqID Ord1 Ord2
------------------------
6 144 4 2
1 144 4 3
4 144 3 5
2 144 2 1
8 144 2 3
Now, I need a single query that, for each MaqID, return the first ID for each subquery following above order. The result should be:
Expected result
MaqID ID
-----------
144 6
12 5
I have already try distinct conbination of TOP a MAX, but TOP result only one result and i need one for each MaqID, and for Max I have not field to maximize.
To sumarize: I need the first ID for each MaqID from a subquery in a specific order
Any ideas? Thanks!
You can do this using row_number():
select t.*
from (select t.*,
row_number() over (partition by macid Order1 DESC, Order2) as seqnum
from mytable t
) t
where seqnum = 1;