Joining rows in Acces under specific conditions - ms-access

I am working in access 2010 I have a table which has the following format:
ID BOORP BEGIN_DIEPTE EIND_DIEPTE TEXTUUR1
1 148000 0 10 ZK
2 148000 20 60 ZK
3 148000 60 80 MK
4 148000 80 110 MK
5 148000 110 130 ZK
6 148000 130 160 -
7 148000 160 220 ZZL
8 148000 220 250 -
9 148000 250 300 MK
10 148001 0 20 ZK
11 148001 20 40 -
12 148001 40 210 ZZL
13 148001 210 310 ZZL
What i want is to join certain rows which have the same texture under the following conditions:
1) rows must have the same BOORP in order to be merged
2) only consecutive rows may be merged
The result should look like this:
ID BOORP BEGIN_DIEPTE EIND_DIEPTE TEXTUUR1
1 148000 0 60 ZK
3 148000 60 110 MK
5 148000 110 130 ZK
6 148000 130 160 -
7 148000 160 220 ZZL
8 148000 220 250 -
9 148000 250 300 MK
10 148001 0 20 MK
11 148001 20 40 -
12 148001 40 310 ZZL
It is especially the 2nd condition i'm having problem with.
Any suggestions?

That's quite a complex task as an SQL-only solution.
If you want to do it in one query, you can use the following solution (tested on your sample data):
SELECT e.ID, e.BOORP, e.BEGIN_DIEPTE, e.EINDDIEPTE As EIND_DIEPTE, e.TEXTUUR1
FROM
(
SELECT a.ID, a.BOORP, a.BEGIN_DIEPTE, IIF(b.ID Is Null, a.EIND_DIEPTE, b.EIND_DIEPTE) AS EINDDIEPTE, a.TEXTUUR1, b.ID As IDJoined
FROM TestTable a
LEFT JOIN
(
SELECT c.*, (SELECT Max(d.ID) FROM TestTable d WHERE d.ID < c.ID) As PreviousID
FROM TestTable c
) As b
ON b.PreviousID = a.ID AND b.BOORP = a.BOORP AND a.TEXTUUR1 = b.TEXTUUR1
) AS e
WHERE e.ID NOT IN (
SELECT b.ID
FROM TestTable a
INNER JOIN
(
SELECT c.*, (SELECT Max(d.ID) FROM TestTable d WHERE d.ID < c.ID) As PreviousID
FROM TestTable c
) As b
ON b.PreviousID = a.ID AND b.BOORP = a.BOORP AND a.TEXTUUR1 = b.TEXTUUR1
)
It's quite a lot of subqueries, and a bit too much to explain in depth. Simply put, the most inner subquery (query b) LEFT JOINs on equal BOORP and TEXTUUR1 and where the ID is the previous ID, then the outer subquery (query e) takes the result, and removes all the entries that have been joined with another entry.
Note that this joins 2 entries together, not more than that. If you want to join more than 2 entries together, you can just run a similar query on the result of this one.

Related

USING OF SUBQUERY

below is database and table details.
database name - mis_v1
table 1 name - trips
table 2 name - client
i tried below queries
Query 1
select cl.client_name CLIENT
, count(t.trip_type) TRIPS
, count(distinct t.vehicle_reg_no) VEHICLES
from mis_v1.trips t
JOIN mis_v1.client cl
ON cl.id = t.client_id
group
by cl.client_name;
Query 1 result
CLIENT TRIPS VEHICLES
anz-ABlr 118 16
citrix-CBlr 159 15
dxc-DBlr 26 5
Eps-Blr 116 24
goc-GocHyd 191 10
Unisys-BLR 192 55
Wipro-Ncr 86 33
Wipro-Pnq 10 5
Query 2
select cl.client_name CLIENT
, count(t.trip_delay_reason) LATE_TRIPS
FROM mis_v1.trips t
JOIN mis_v1.client cl
ON cl.id = t.client_id
where t.trip_delay_reason = "DRIVER"
group
by cl.client_name;
Query 2 result
CLIENT LATE_TRIPS
anz-ABlr 53
citrix-CBlr 25
dxc-DBlr 1
Wipro-Ncr 1
goc-GocHyd 17
I need result as below
CLIENT TRIPS VEHICLES LATE_TRIPS
anz-ABlr 118 16 53
citrix-CBlr 159 15 25
dxc-DBlr 26 5 1
Eps-Blr 116 24 -
goc-GocHyd 191 10 17
Unisys-BLR 192 55 -
Wipro-Ncr 86 33 1
Wipro-Pnq 10 5 -
Kindly give me solution.Thanks in advance
If I understood you correctly, you need something like this:
select cl.client_name CLIENT
, count(t.trip_type) TRIPS
, count(distinct t.vehicle_reg_no) VEHICLES
, coalesce(cast(count(case when t.trip_delay_reason = "DRIVER" then 1 else null end) as char), '-') LATE_TRIPS
from mis_v1.trips t
JOIN mis_v1.client cl
ON cl.id = t.client_id
group
by cl.client_name;
So, please read more about COUNT aggreagate function and probably CASE operator

Retrieve a column with the list of object_id's that occurs together more than once and a second column with the count of how many times it occurs

Note that object_id's 18,10 and 21 are associated to the cart_id 3 once. I wanna know whether the combination occurs again in another cart_id and how many times does that occurs over all the rows existent. I expect two columns as a resultset "combination" and "combination_occurrence_count"
It is quite complicated task to check all possible combinations as it is too many of them.
However, if you simplify your requirements a bit, you can get something useful.
Lets start with finding all combinations of two items. At the beginning you can try the following query:
SELECT
c1.cart_id AS cart1_id
, c1.object_id AS object1_id
, c2.object_id AS object2_id
, cx1.cart_id AS cartX_id
, cx1.object_id AS objectX1_id
, cx2.object_id AS objectX2_id
FROM
cart_item AS c1
INNER JOIN cart_item AS c2 ON (
c2.cart_id = c1.cart_id
AND c2.object_id > c1.object_id
)
INNER JOIN cart_item AS cx1 ON (
cx1.cart_id > c1.cart_id
AND cx1.object_id = c1.object_id
)
INNER JOIN cart_item AS cx2 ON (
cx2.cart_id = cx1.cart_id
AND cx2.object_id = c2.object_id
)
ORDER BY
c1.cart_id
, c1.object_id
, c2.object_id
, cx1.cart_id
, cx1.object_id
, cx2.object_id
There are two ideas behind the query:
Get all possible combinations of two object ids that are exist in
carts. Carts with only one item will be excluded. The only existing
combinations would be analyzed (instead of all possible combinations). [c1 & c2]
Find other carts that have the same object ids combinations [cx1 & cx2]
The results would be something like this:
cart1_id object1_id object2_id cartX_id objectX1_id objectX2_id
3 10 18 30 10 18
3 10 18 31 10 18
3 10 21 30 10 21
3 18 21 30 18 21
30 10 18 31 10 18
Then you can group these results to get "the most popular" pairs:
SELECT
cx1.object_id AS object1_id
, cx2.object_id AS object2_id
, 1 + COUNT(DISTINCT cx1.cart_id) AS cnt
FROM
cart_item AS c1
INNER JOIN cart_item AS c2 ON (
c2.cart_id = c1.cart_id
AND c2.object_id > c1.object_id
)
INNER JOIN cart_item AS cx1 ON (
cx1.cart_id > c1.cart_id
AND cx1.object_id = c1.object_id
)
INNER JOIN cart_item AS cx2 ON (
cx2.cart_id = cx1.cart_id
AND cx2.object_id = c2.object_id
)
GROUP BY
cx1.object_id
, cx2.object_id
ORDER BY
cnt DESC
LIMIT
20
Results:
object1_id object2_id cnt
10 18 3
10 21 2
18 21 2
So pair 10 + 18 is the most popular and are exist in 3 carts.
Pairs 10 + 21 and 18 + 21 are in 2 different carts.
You can continue and do something like this for 3-objects combinations.
P.S. I used the following data set (added a few rows to your data to get a bit more interesting results):
id cart_id object_id
10 2 24
9 3 10
3 3 18
19 3 21
12 4 24
1 7 30
5 9 24
2 11 10
20 14 12
14 14 18
8 14 27
13 15 11
7 16 9
18 16 13
15 20 11
6 21 6
4 23 5
17 23 6
16 25 16
11 29 11
23 30 1
21 30 10
22 30 18
24 30 21
25 31 10
26 31 18
P.P.S. I have not spent too much time on this so it is possible that I missed something in queries. However, I hope you understand the general idea.
The following returns the list of carts with all three objects:
select cart_id
from t
where object_id in (18, 10, 21)
group by cart_id
having count(distinct cart_id) = 3;
select group_concat(`app_item`.`object_id`) as `combination`
from `app_item`
group by `app_item`.`cart_id`
The query return a "combination" resultset as I was looking for:
Since I cannot group again using the "combination" and then make a count of occurrences for each combination and then get the "combination_occurrence_count" it contains, I am now doing this through a method in the application as following
and now I can display an array as key/pair like "combination" => "occurrence count" as following

Select corresponding value from second table (Mysql)

Struggling with some sql, would appreciate some guidance.
Have two tables logs and sense
logs –
assetid ts nodeid status
1 2017-10-26 14:00:10 73 240
2 2017-10-26 14:00:06 21 160
3 2017-10-26 14:00:04 18 230
4 2017-10-26 14:00:02 19 400
5 2017-10-26 14:00:00 21 190
1 2017-10-26 13:20:08 18 20
2 2017-10-26 13:06:10 20 160
3 2017-10-26 13:03:04 17 230
sense –
status value
20 5
160 37
190 39
230 56
240 58
400 90
Trying to find the correct syntax to only show the latest record (in datetime) of each assetid and then show the corresponding value from the sense table (based on the matching status in both tables) to produce –
assetid ts nodeid status value
1 2017-10-26 14:00:10 73 240 58
2 2017-10-26 14:00:06 21 160 37
3 2017-10-26 14:00:04 18 230 56
4 2017-10-26 14:00:02 19 400 90
5 2017-10-26 14:00:00 21 190 39
Have tried –
Select assetid, ts, nodeid, status, value
From
logs
Join sense X on X.status = logs.status
Group by assetid
Order by ts DESC
But this only outputs 1 row (instead of 5)
assetid ts nodeid status value
1 2017-10-26 14:00:10 73 240 58
Removing
Join sense X on X.status = logs.status
of course outputs all records but that is not required.
Thoughts appreciated.
Regards
Active
Actually your query is returning 5 rows, 1 for each id. But it won't return rows with latest ts for each id. You can verify this by clicking on the link for demo. You can compare results of both queries.
To achieve this task,following query will help you:
Select l.assetid, l.ts, logs.nodeid, X.status, X.value
From
logs
inner Join sense X on X.status = logs.status
inner join (select assetid, max(ts) as ts from logs group by assetid) l
on l.assetid = logs.assetid and logs.ts = l.ts
Group by l.assetid
Order by l.ts DESC;
Click here for Demo
EDIT:
If dataype of ts is string then replace max(ts) in above query with:
max(str_to_date(ts,'%d%m%y'))
Feel free to ask any doubts.
Hope it helps!
Try this
Select a1.assetid, MAX(a1.ts), a1.nodeid, a1.status, X.value
From
logs a1
inner join sense X on X.status = a1.status
Group by assetid, a1.nodeid, a1.status, X.value
Order by ts DESC
Use GROUP BY to find minimum for each assetid and then JOIN with the logs and sense
Select *
FROM logs l
JOIN sense s ON s.status = l.status
JOIN
(
Select assetid, max(ts) maxts
From logs
Group by assetid
) t ON t.assetid = l.assetid and l.ts = t.maxts
demo
On MY SQL 8.0.2
WITH CTE as
(
Select A.assetid, A.ts, A.nodeid, A.status, B.value, row_number() over(PARTITION BY A.assetid ORDER BY A.ts DESC) AS rn
from logs as A
inner join sense B ON A.status=B.status
)
SELECT *
FROM CTE
WHERE rn='1';

Find repeated battles

I have one table with the following fields:
battle_id, winner, looser
1 200 44
2 55 366
3 44 200
4 123 200
5 200 44
6 55 366
7 177 205
8 188 211
9 366 55
10 55 366
right now it has about 1300 records (its small), and there are about 400 players, in each battle there can only be a winner and a looser (there are no draws)
how can i find all the repeated battles? i do not want to find all the repeated battles of one player, i do want to know all the repeated battles of all the players...i know that i cam make a recursive function in php that iterates over all the battles and assign them to a matrix, but just for fun...is there a way to do it only on mysql?
And how can i optimize the table to find the repeated battles more quickly?
regards
EDIT:
For example i want the query to show:
battle_id, winner, looser
1 200 44
2 55 366
3 44 200
5 200 44
6 55 366
9 366 55
10 55 366
This should work, using a self-join could result in many duplicated entries
SQLFIDDLE
SELECT
t1.battle_id,
t1.winner,
t1.loser
FROM
your_table t1
WHERE
EXISTS (
SELECT
1
FROM
your_table t2
WHERE
( ( t1.winner = t2.winner
AND t1.loser = t2.loser )
OR ( t1.loser = t2.winner
AND t1.winner = t2.loser ) )
AND t1.battle_id <> t2.battle_id
)
try this:
SELECT b1.battle_id,
b1.winner,
b1.looser
FROM battles as b1
group by b1.battle_id, b1.winner, b1.looser
having count(*)>=2

change multi rows to one row-multi column

For some reason i have to do this. i have a query that have result like this :
limit usage tariff total
0 10 10 700 7000
11 20 10 900 9000
21 30 10 1800 18000
31 > 11 2700 29700
the query return 4 rows maximum (like above) or sometime just 3 rows.
I want to change the rows to just one row and multi column like this (the list below just one row):
limit1 usage1 tariff1 total1 limit2 usage2 tariff2 total2
0 10 10 700 7000 11 20 10 900 9000
limit3 usage3 tariff3 total3 limit4 usage4 tariff4 total4
21 30 10 1800 18000 31 > 11 2700 29700
if the query return just 3 rows, the values in column limit4 until total4 will be empty. I dont know how to do like that.
EDITED
I add one ID column so the list will be :
ID limit usage tariff total
1 0 10 10 700 7000
2 11 20 10 900 9000
3 21 30 10 1800 18000
4 31 > 11 2700 29700
I try to make it one row like this :
SELECT e.*,f.id AS id4,f.limit AS limit4,f.usage AS usage4,f.tariff AS tariff4,f.total AS total4
FROM
(SELECT c.*,d.id AS id3,d.limit AS limit3,d.usage AS usage3,d.tariff AS tariff3,d.total AS total3
FROM
(SELECT b.id AS id1,b.limit AS limit1,b.usage AS usage1,b.tariff AS tariff1,b.total AS total1,
a.id AS id2,a.limit AS limit2,a.usage AS usage2,a.tariff AS tariff2,a.total AS total2
FROM testtariff a
INNER JOIN testtariff b ON a.id!=b.id
LIMIT 1) c INNER JOIN testtariff d ON c.id1 != d.id AND c.id2 != d.id
LIMIT 1) e INNER JOIN testtariff f ON e.id1 != f.id AND e.id2 != f.id
AND e.id3 != f.id
LIMIT 1
it work as i expected for 4 rows but not work for 3 rows. should i use cursor ?
This is generally called a "pivot". Here's how you do it:
select
'0 10' as limit1,
sum(limit between 0 and 10 * usage) as usage1,
sum(limit between 0 and 10 * tariff) as tariff1,
sum(limit between 0 and 10 * usage * tariff) as total1,
'11 20' as limit2,
sum(limit between 11 and 20 * usage) as usage2,
sum(limit between 11 and 20 * tariff) as tariff2,
sum(limit between 11 and 20 * usage * tariff) as total2,
-- etc
from mytable
group by 1,5 -- etc
This works because limit between x and x is 1 if true and 0 if false, so using multiplying by this is a simple way to filter the results into different groups.