How can i improve query for efficiency in mysql - mysql

Senario:
I'm working with two tables, (structure below)
expenses_tb person_expenses_tb
+----+-----------+ +----+------+-------------+-----------+--------+
| id | expenses | | id | year | expenses_id | person | amount |
+----+-----------+ +----+------+-------------+-----------+--------+
| 1 | Bus | | 1 | 2007 | 1 | Will | 20 |
| 2 | Food | | 2 | 2007 | 2 | Will | 200 |
| 3 | Clothes | | 3 | 2007 | 4 | Will | 1000 |
| 4 | Girlfriend| | 4 | 2007 | 5 | Will | 20 |
| 5 | Taxi | | 5 | 2008 | 3 | Will | 500 |
+----+-----------+ | 6 | 2008 | 5 | Will | 100 |
| 7 | 2008 | 2 | Holly | 200 |
| 8 | 2007 | 5 | Holly | 850 |
| .. | 2013 | ... | .... | ... |
I have tried two different queries.
SELECT person, expenses,
CASE expense_id WHEN 1 THEN amount END AS 'bus',
CASE expense_id WHEN 2 THEN amount END AS 'food',
CASE expense_id WHEN 3 THEN amount END AS 'clothes',
CASE expense_id WHEN 4 THEN amount END AS girlfriend',
CASE expense_id WHEN 5 THEN amount END AS 'taxi'
FROM person_expenses_tb p
JOIN expenses e ON e.id=p.expenses_id
WHERE p.year = 2008
GROUP BY p.person
The query above runs fast but does not produce the desired output.
Second query i tried was
SELECT person, expenses,
(SELECT amount FROM person_expenses_tb p_bus WHERE expense_id = 1 AND p_bus.person = p.person AND year=2008) AS 'bus',
(SELECT amount FROM person_expenses_tb p_bus WHERE expense_id = 2 AND p_bus.person = p.person AND year=2008) AS 'food',
(SELECT amount FROM person_expenses_tb p_bus WHERE expense_id = 3 AND p_bus.person = p.person AND year=2008) AS 'clothes',
(SELECT amount FROM person_expenses_tb p_bus WHERE expense_id = 4 AND p_bus.person = p.person AND year=2008) AS girlfriend',
(SELECT amount FROM person_expenses_tb p_bus WHERE expense_id = 5 AND p_bus.person = p.person AND year=2008) AS 'taxi'
FROM person_expenses_tb p
JOIN expenses e ON e.id=p.expenses_id
WHERE p.year = 2008
GROUP BY p.person
this query produced the right result but its extremely slow when the [person_expenses_tb] has over 2000 records.
the desired result for 2007: I have a i pass the requested year to the query.
+--------+------+-----+------+---------+------------+------+
| person | Year | Bus | Food | Clothes | Girlfriend | Taxi |
+--------+------+-----+------+---------+------------+------+
| Will | 2007 | 20 | 20 | 0 | 1000 | 20 |
| Holly | 2007 | 0 | 0 | 0 | 0 | 850 |
| ... | ... | ... | ... | ... | ... | ... |
i would love help on how to improve the query for it to run faster and if there is another way of getting the desired output i would appreciate the help.
Thank you.

The first query is the right approach (in general). You just need aggregation functions:
SELECT person,
sum(CASE p.expenses_id WHEN 1 THEN amount END) AS bus,
sum(CASE p.expenses_id WHEN 2 THEN amount END) AS food,
sum(CASE p.expenses_id WHEN 3 THEN amount END) AS clothes,
sum(CASE p.expenses_id WHEN 4 THEN amount END) AS girlfriend,
sum(CASE p.expenses_id WHEN 5 THEN amount END) AS taxi
FROM person_expenses_tb p
WHERE p.year = 2008
GROUP BY p.person;
Your version doesn't work because of a "feature" of MySQL. p.expenses_id is not in the group by clause. In that case, MySQL chooses an arbitrary value. Hence, only one of the columns will be populated. The aggregation function fixes this problem.
Because you are using expense_id for pivoting, you don't need the join to the reference table. I also removed the single quotes from the names of the columns. Although MySQL allows this, it is bad practice. Just use single quotes for string constants. If you need to escape a name, use back quotes or double quotes.
(I also changed expense_id to expenses_id to match the naming in your sample data.)

Related

Only display Card payments

I designed a till system about 6 years ago, and while the code is dismal and horrible to look at, it is still going and the cafe I designed it for has been using it all this time.
However, they have recently acquired a card machine, and so now when they want to view all the sales for the day they wnat to see cash vs card in two separate tables.
This is proving tricky and the SQL for it is stumping me - I can't get my head around it.
Here are the tables involved:
categories
+----+-------------------+---------+------------+
| id | name | display | ts |
+----+-------------------+---------+------------+
| 1 | Drinks | 1 | 2016-10-14 |
| 2 | General Snacks | 1 | 2016-10-14 |
| 3 | Lunch Options | 1 | 2016-10-14 |
| 4 | Conference Drinks | 1 | 2016-10-14 |
+----+-------------------+---------+------------+
products
+----+-----------------+-------+------+-----+---------+------------+
| id | name | price | cost | cID | display | ts |
+----+-----------------+-------+------+-----+---------+------------+
| 1 | English Tea | 0.6 | 0.09 | 1 | 1 | 2018-02-15 |
| 2 | Speciality Teas | 0.8 | 0.17 | 1 | 1 | 2018-02-15 |
| 3 | Crisps | 0.6 | 0.41 | 3 | 1 | 2018-02-15 |
| 4 | Chocolate Bar | 0.6 | 0.5 | 3 | 1 | 2018-02-15 |
+----+-----------------+-------+------+-----+---------+------------+
receipts
+----+-----+-----+----------+------------+
| id | oID | pID | quantity | ts |
+----+-----+-----+----------+------------+
| 1 | 1 | 26 | 1 | 2013-11-21 |
| 2 | 2 | 6 | 2 | 2013-11-21 |
| 3 | 3 | 2 | 1 | 2013-11-21 |
| 4 | 4 | 3 | 1 | 2013-11-21 |
+----+-----+-----+----------+------------+
sales
+----+-------+----------+------+------+--------+------------+
| id | total | tendered | flag | card | userID | ts |
+----+-------+----------+------+------+--------+------------+
| 1 | 1 | 1 | 0 | 0 | 4 | 2013-11-21 |
| 2 | 2 | 2 | 0 | 0 | 4 | 2013-11-21 |
| 3 | 0.6 | 0.6 | 0 | 0 | 4 | 2013-11-21 |
| 4 | 0.6 | 0.6 | 0 | 0 | 4 | 2013-11-21 |
+----+-------+----------+------+------+--------+------------+
Please bear in mind that I wrote this a long time ago and I'm aware that its not perfect. Just to explain the above, oID stands for orderID but really should be salesID and links to the sales table ID, and pID stands for productID and is a foreign key linking to the products table. Similarily, cID is really categoryID.
Okay So the cafe manager had requested a table that looks like the following:
+---------------+-----+------+-------+------------+-----------+
| Drinks | Qty | Cost | Price | Cost-Total | Qty-total |
+---------------+-----+------+-------+------------+-----------+
| Juice Carton | 2 | 33p | 60p | 66p | £1.20 |
| Filter Coffee | 11 | 20p | 80p | £2.20 | £8.80 |
| Sub Total | 13 | | | £2.86 | £10.00 |
| Grand Total | 13 | | | £2.86 | £10.00 |
+---------------+-----+------+-------+------------+-----------+
Which has been fine, I've used the following SQL statement to produce this:
SELECT
categories.name AS category, products.name, pID,
(SELECT SUM(quantity) FROM receipts s WHERE s.pID = r.pID AND DATE(s.ts) = CURDATE()) AS quantity,
products.price,
products.cost
FROM receipts r
LEFT JOIN products ON r.pID = products.id
LEFT JOIN categories ON products.cID = categories.id
WHERE DATE(r.ts) = CURDATE()
GROUP BY r.pID ORDER BY categories.name;
However now I need to display two tables, one for card and one for cash. Now the card payments are marked in the sales table with a 1 in the card column. So I tried writing this:
SELECT
categories.name AS category, products.name, pID,
(SELECT SUM(quantity) FROM receipts s WHERE s.pID = r.pID AND DATE(s.ts) = CURDATE()) AS quantity,
products.price,
products.cost
FROM receipts r
LEFT JOIN products ON r.pID = products.id
LEFT JOIN sales x on r.oID = x.id
LEFT JOIN categories ON products.cID = categories.id
WHERE DATE(r.ts) = CURDATE() AND x.card = 1
GROUP BY r.pID ORDER BY categories.name;
However it is just displaying the same data as the first query. I know where the problem is - its in the embedded SELECT statement (AS quantity), as I'm not specifying in there whether its a card payment or a cash payement. I thought that just by adding x.card = 1 a the end would do it, but evidentally not.
Can anyone help me fix this SQL problem? How can I get the card condition into the embedded SQL, as it is retrieving from receipts and receipts does not hold information as to wether its a card payment or not?
I'm lost as to how to proceed really. All help will be appreciated!
In it's basic form:
SELECT * FROM Sales WHERE card = 1
Will display just the card payments
This will give you any sales from today:
SELECT *
FROM
categories,
products,
sales,
reciepts,
LEFT JOIN
products ON reciepts.pID
sales ON reciepts.oID
categories ON products.cID
WHERE DATE(s.ts) = CURDATE()
AND sales.card = 1
`
So what you have there is correct. It's something else you are missing...
From what I can see so far you haven't selected the sales table which could be your issue.
Have you tried running the code in SQL management studio and seeing what the result is?

Query with dynamic date intervals

Given a statuses table that holds information about products availability, how do I select the date that corresponds to the 1st day in the latest 20 days that the product has been active?
Yes I know the question is hard to follow. I think another way to put it would be: I want to know how many times each product has been sold in the last 20 days that it was active, meaning the product could have been active for years, but I'd only want the sales count from the latest 20 days that it had a status of "active".
It's something easily doable in the server-side (i.e. getting any collection of products from the DB, iterating them, performing n+1 queries on the statuses table, etc), but I have hundreds of thousands of items so it's imperative to do it in SQL for performance reasons.
table : products
+-------+-----------+
| id | name |
+-------+-----------+
| 1 | Apple |
| 2 | Banana |
| 3 | Grape |
+-------+-----------+
table : statuses
+-------+-------------+---------------+---------------+
| id | name | product_id | created_at |
+-------+-------------+---------------+---------------+
| 1 | active | 1 | 2018-01-01 |
| 2 | inactive | 1 | 2018-02-01 |
| 3 | active | 1 | 2018-03-01 |
| 4 | inactive | 1 | 2018-03-15 |
| 6 | active | 1 | 2018-04-25 |
| 7 | active | 2 | 2018-03-01 |
| 8 | active | 3 | 2018-03-10 |
| 9 | inactive | 3 | 2018-03-15 |
+-------+-------------+---------------+---------------+
table : items (ordered products)
+-------+---------------+-------------+
| id | product_id | order_id |
+-------+---------------+-------------+
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 3 | 1 | 3 |
| 4 | 1 | 4 |
| 5 | 1 | 5 |
| 6 | 2 | 3 |
| 7 | 2 | 4 |
| 8 | 2 | 5 |
| 9 | 3 | 5 |
+-------+---------------+-------------+
table : orders
+-------+---------------+
| id | created_at |
+-------+---------------+
| 1 | 2018-01-02 |
| 2 | 2018-01-15 |
| 3 | 2018-03-02 |
| 4 | 2018-03-10 |
| 5 | 2018-03-13 |
+-------+---------------+
I want my final results to look like this:
+-------+-----------+----------------------+--------------------------------+
| id | name | recent_sales_count | date_to_start_counting_sales |
+-------+-----------+----------------------+--------------------------------+
| 1 | Apple | 3 | 2018-01-30 |
| 2 | Banana | 0 | 2018-04-09 |
| 3 | Grape | 1 | 2018-03-10 |
+-------+-----------+----------------------+--------------------------------+
So this is what I mean by latest 20 active days for e.g. Apple:
It was last activated at '2018-04-25'. That's 4 days ago.
Before that, it was inactive since '2018-03-15', so all these days until '2018-04-25' don't count.
Before that, it was active since '2018-03-01'. That's more 14 days until '2018-03-15'.
Before that, inactive since '2018-02-01'.
Finally, it was active since '2018-01-01', so it should only count the missing 2 days (4 + 14 + 2 = 20) backwards from '2018-02-01', resulting in date_to_start_counting_sales = '2018-01-30'.
With the '2018-01-30' date in hand, I'm then able to count Apple orders in the last 20 active days: 3.
Hope that makes sense.
Here is a fiddle with the data provided above.
I've got a standard SQL solution, that does not use any window function as you are on MySQL 5
My solution requires 3 stacked views.
It would have been better with a CTE but your version doesn't support it. Same goes for the stacked Views... I don't like to stack views and always try to avoid it, but sometimes you have no other choice, because MySQL doesn't accept subqueries in FROM clause for Views.
CREATE VIEW VIEW_product_dates AS
(
SELECT product_id, created_at AS active_date,
(
SELECT created_at
FROM statuses ti
WHERE name = 'inactive' AND ta.created_at < ti.created_at AND ti.product_id=ta.product_id
GROUP BY product_id
) AS inactive_date
FROM statuses ta
WHERE name = 'active'
);
CREATE VIEW VIEW_product_dates_days AS
(
SELECT product_id, active_date, inactive_date, datediff(IFNULL(inactive_date, SYSDATE()),active_date) AS nb_days
FROM VIEW_product_dates
);
CREATE VIEW VIEW_product_dates_days_cumul AS
(
SELECT product_id, active_date, ifnull(inactive_date,sysdate()) AS inactive_date, nb_days,
IFNULL((SELECT SUM(V2.nb_days) + V1.nb_days
FROM VIEW_product_dates_days V2
WHERE V2.active_date >= IFNULL(V1.inactive_date, SYSDATE()) AND V1.product_id=V2.product_id
),V1.nb_days) AS cumul_days
FROM VIEW_product_dates_days V1
);
The final view produce this :
| product_id | active_date | inactive_date | nb_days | cumul_days |
|------------|----------------------|----------------------|---------|------------|
| 1 | 2018-01-01T00:00:00Z | 2018-02-01T00:00:00Z | 31 | 49 |
| 1 | 2018-03-01T00:00:00Z | 2018-03-15T00:00:00Z | 14 | 18 |
| 1 | 2018-04-25T00:00:00Z | 2018-04-29T11:28:39Z | 4 | 4 |
| 2 | 2018-03-01T00:00:00Z | 2018-04-29T11:28:39Z | 59 | 59 |
| 3 | 2018-03-10T00:00:00Z | 2018-03-15T00:00:00Z | 5 | 5 |
So it aggregates all active periods of all products, it counts the number of days for each period, and the cumulative days of all past active periods since current date.
Then we can query this final view to get the desired date for each product. I set a variable for your 20 days, so you can change that number easily if you want.
SET #cap_days = 20 ;
SELECT PD.id, Pd.name,
SUM(CASE WHEN o.created_at > PD.date_to_start_counting_sales THEN 1 ELSE 0 END) AS recent_sales_count ,
PD.date_to_start_counting_sales
FROM
(
SELECT p.*,
(CASE WHEN LowerCap.max_cumul_days IS NULL
THEN ADDDATE(ifnull(HigherCap.min_inactive_date,sysdate()),(-#cap_days))
ELSE
CASE WHEN LowerCap.max_cumul_days < #cap_days AND HigherCap.min_inactive_date IS NULL
THEN ADDDATE(ifnull(LowerCap.max_inactive_date,sysdate()),(-LowerCap.max_cumul_days))
ELSE ADDDATE(ifnull(HigherCap.min_inactive_date,sysdate()),(LowerCap.max_cumul_days-#cap_days))
END
END) as date_to_start_counting_sales
FROM products P
LEFT JOIN
(
SELECT product_id, MAX(cumul_days) AS max_cumul_days, MAX(inactive_date) AS max_inactive_date
FROM VIEW_product_dates_days_cumul
WHERE cumul_days <= #cap_days
GROUP BY product_id
) LowerCap ON P.id=LowerCap.product_id
LEFT JOIN
(
SELECT product_id, MIN(cumul_days) AS min_cumul_days, MIN(inactive_date) AS min_inactive_date
FROM VIEW_product_dates_days_cumul
WHERE cumul_days > #cap_days
GROUP BY product_id
) HigherCap ON P.id=HigherCap.product_id
) PD
LEFT JOIN items i ON PD.id = i.product_id
LEFT JOIN orders o ON o.id = i.order_id
GROUP BY PD.id, Pd.name, PD.date_to_start_counting_sales
Returns
| id | name | recent_sales_count | date_to_start_counting_sales |
|----|--------|--------------------|------------------------------|
| 1 | Apple | 3 | 2018-01-30T00:00:00Z |
| 2 | Banana | 0 | 2018-04-09T20:43:23Z |
| 3 | Grape | 1 | 2018-03-10T00:00:00Z |
FIDDLE : http://sqlfiddle.com/#!9/804f52/24
Not sure which version of MySql you're working with, but if you can use 8.0, that version came out with a lot of functionality that makes things slightly more doable (CTE's, row_number(), partition, etc.).
My recommendation would be to create a view like in this DB-Fiddle Example, call the view on server side and iterate programatically. There are ways of doing it in SQL, but it'd be a bear to write, test and likely would be less efficient.
Assumptions:
Products cannot be sold during inactive date ranges
Statuses table will always alternate status active/inactive/active for each product. I.e. no date ranges where a certain product is both active and inactive.
View Results:
+------------+-------------+------------+-------------+
| product_id | active_date | end_date | days_active |
+------------+-------------+------------+-------------+
| 1 | 2018-01-01 | 2018-02-01 | 31 |
+------------+-------------+------------+-------------+
| 1 | 2018-03-01 | 2018-03-15 | 14 |
+------------+-------------+------------+-------------+
| 1 | 2018-04-25 | 2018-04-29 | 4 |
+------------+-------------+------------+-------------+
| 2 | 2018-03-01 | 2018-04-29 | 59 |
+------------+-------------+------------+-------------+
| 3 | 2018-03-10 | 2018-03-15 | 5 |
+------------+-------------+------------+-------------+
View:
CREATE OR REPLACE VIEW days_active AS (
WITH active_rn
AS (SELECT *, Row_number()
OVER ( partition BY NAME, product_id
ORDER BY created_at) AS rownum
FROM statuses
WHERE name = 'active'),
inactive_rn
AS (SELECT *, Row_number()
OVER ( partition BY NAME, product_id
ORDER BY created_at) AS rownum
FROM statuses
WHERE name = 'inactive')
SELECT x1.product_id,
x1.created_at AS active_date,
CASE WHEN x2.created_at IS NULL
THEN Curdate()
ELSE x2.created_at
END AS end_date,
CASE WHEN x2.created_at IS NULL
THEN Datediff(Curdate(), x1.created_at)
ELSE Datediff(x2.created_at,x1.created_at)
END AS days_active
FROM active_rn x1
LEFT OUTER JOIN inactive_rn x2
ON x1.rownum = x2.rownum
AND x1.product_id = x2.product_id ORDER BY
x1.product_id);

MySQL Grouping Query

I have a number of tables in my database.
Table: ObjectToPerson
For example if I had a number of entries below in the database:
+----+------------+------------+----------+----------+--------------+
| Id | WeekNumber | Date | PersonId | ObjectId | ObjectTypeId |
+----+------------+------------+----------+----------+--------------+
| 1 | 1 | 2015-11-04 | 1 | 1 | 1 |
| 2 | 1 | 2015-11-04 | 1 | 3 | 2 |
| 3 | 1 | 2015-11-04 | 2 | 2 | 1 |
| 4 | 1 | 2015-11-04 | 2 | 4 | 2 |
+----+------------+------------+----------+----------+--------------+
I am wanting to return the results back as two lines as follows:
+------+------------+----------+----------------------------+----------------------------+
| Week | Date | PersonId | ObjectId(ObjectTypeId = 1) | ObjectId(ObjectTypeId = 2) |
+------+------------+----------+----------------------------+----------------------------+
| 1 | 2015-11-04 | 1 | 1 | 3 |
| 1 | 2015-11-04 | 2 | 2 | 4 |
+------+------------+----------+----------------------------+----------------------------+
I am thinking of some sort of Group By query but I just can't seem to get it right.
Select * From ObjectToPerson
Left Join Objects O On O.Id = ObjectToPerson.ObjectId And ObjectToPerson.ObjectTypeId = 1
Left Join Objects O On O.Id = ObjectToPerson.ObjectId And ObjectToPerson.ObjectTypeId = 2
Can someone explain how I would get to this please?
You could use CASE to only select the ObjectId if the type is correct for the column, then use MAX/GROUP BY to group the result into a single row per person/week/date.
SELECT WeekNumber week, date, personid,
MAX(CASE WHEN ObjectTypeId=1 THEN ObjectId END) Type1,
MAX(CASE WHEN ObjectTypeId=2 THEN ObjectId END) Type2
FROM ObjectToPerson
GROUP BY week, date, personid
An SQLfiddle to test with.
You don't want two joins, you want a WHERE clause;
SELECT * FROM ObjectToPerson
LEFT JOIN Objects O ON O.Id = ObjectToPerson.ObjectId
WHERE ObjectToPerson.ObjectTypeId IN(1,2)

JOIN TWO TABLES [duplicate]

This question already has answers here:
How can I return pivot table output in MySQL?
(10 answers)
Closed 8 years ago.
I have two tables: 'Project' and 'Project Monthly'.
| PROJECT_ID | TITLE | | ID | PROJECT_ID | MONTH | EXPENSE |
----------------------- --------------------------------------
| 1 | title1 | | 1 | 1 | 1 | 100 |
| 2 | title2 | | 2 | 1 | 2 | 2000 |
| 3 | title3 | | 3 | 1 | 3 | 900 |
| 4 | 1 | 4 | 900 |
| 5 | 2 | 1 | 200 |
| 6 | 2 | 2 | 200 |
| 7 | 3 | 1 | 500 |
I would like to have a table like this:
| PROJECT_ID | TITLE | MONTH_1 | MONTH_2 | MONTH_3 | MONTH_4 |
---------------------------------------------------------------
| 1 | title1 | 100 | 2000 | 900 | 900 |
| 2 | title2 | 200 | 200 | NULL| NULL|
| 3 | title3 | 500 | NULL | NULL| NULL|
Can I realize it only with JOIN and without subqueries?
Thanks!
Turning rows into columns is called pivoting. One approach is to group by each project. The group will become a single row. Inside the group, you define one column per month. The column sums up the expenses for one particular month:
select p.PROJECT_ID
, p.TITLE
, sum(case when m.month = 1 then m.expense end) as MONTH_1
, sum(case when m.month = 2 then m.expense end) as MONTH_2
...
from project p
join monthly m
on p.PROJECT_ID = m.PROJECT_ID
group by
p.PROJECT_ID
, p.TITLE
try like this
select p.PROJECT_ID,p.TITLE,
case when month=1 then EXPENSE end as Month_1,
case when month=2 then EXPENSE end as Month_2,
case when month=3 then EXPENSE end as Month_3,
case when month=4 then EXPENSE end as Month_4
from Project p inner join ProjectMonthly' pm on p.PROJECT_ID=pm.PROJECT_ID
You can do so by using case with max to get the desired result set,below query will only give the results for 4 months if you have more than 4 months then you have to write cases for all months with a max to pick greater value among the values for a month,i have used inner join so the projects that exists in ProjectMonthly only these projects will be returned if any project has no monthly data and you still want it to return the results the change inner join to left join
SELECT p.PROJECT_ID,p.TITLE,
MAX(CASE WHEN MONTH=1 THEN EXPENSE END) AS Month_1,
MAX(CASE WHEN MONTH=2 THEN EXPENSE END) AS Month_2,
MAX(CASE WHEN MONTH=3 THEN EXPENSE END) AS Month_3,
MAX(CASE WHEN MONTH=4 THEN EXPENSE END) AS Month_4
FROM Project p
INNER JOIN ProjectMonthly pm
ON p.PROJECT_ID=pm.PROJECT_ID
GROUP BY p.PROJECT_ID
Fiddle Demo

Sum up values in SQL once all values are available

I have events flowing into a MySQL database and I need to group and sum the events to transactions and store away into another table. The data looks like:
+----+---------+------+-------+
| id | transid | code | value |
+----+---------+------+-------+
| 1 | 1 | b | 12 |
| 2 | 1 | i | 23 |
| 3 | 2 | b | 34 |
| 4 | 1 | e | 45 |
| 5 | 3 | b | 56 |
| 6 | 2 | i | 67 |
| 7 | 2 | e | 78 |
| 8 | 3 | i | 89 |
| 9 | 3 | i | 90 |
+----+---------+------+-------+
The events arrive in batches and I would like to create the transaction by summing up the values for each transid, like:
select transid, sum(value) from eventtable group by transid;
but only after all the events for that transid have arrived. That is determined by the event with the code e (b for the beginning, e for the end and i for varying amount of intermediates). Being a novice in SQL, how could I implement the requirement for the existance of the end code before the summing?
Perhaps with having:
select transid, sum(value)
from eventtable
group by transid
having max(case code when 'e' then 1 end)=1;
select transid, sum(value) from eventtable
group by transid
HAVING COUNT(*) = 3
you should count the records in the group. So when there is (b)egin, (i)?? don't know what it is and (e)nd this group is not filtered out.