Laravel calculate sum of two columns with a condition - mysql

I have this Warehouse collection I got from the database
[
{
"id": 1,
"warehouse": "India"
"sales": [
{
"id": 1,
"warehouse_id": 1,
"price": "120.00",
"quantity": 1000,
"status": 1
},
{
"id": 2,
"warehouse_id": 1,
"price": "20.00",
"quantity": 100,
"status": 1
},
{
"id": 3,
"warehouse_id": 1,
"price": "40.00",
"quantity": 1000,
"status": 2
}
]
},
{
"id": 2,
"warehouse": "Malaysia"
"sales": [
{
"id": 4,
"warehouse_id": 2,
"price": "160.00",
"quantity": 100,
"status": 1
}
]
}
]
I want to calculate the total income for each warehouse
Total income is calculated based on the sale status attribute
If status = 1, the products are delivered so it should add price * quantity to the total income
If status = 2, the products are returned so it should subtract price * quantity from the total income
A basic example for India warehouse:
total_income = 120*1000 + 20*100 - 40*1000
And for Malaysia:
total_income = 160*100
I tried using Warehouse::withSum(); but it didn't get me anywhere.
I'm wondering if there's a good way to do with collections

You could just pass a few callbacks to the collection's sum() method:
$warehouses_collection->map(function ($warehouse) {
return (object) [
'id' => $warehouse->id,
'warehouse' => $warehouse->warehouse,
'total_income' => collect($warehouse->sales)->sum(function ($sale) {
((int) $sale->price) * $sale->quantity * ($sale->status == 1 ? 1 : -1)
})
];
});
WithSum is a bit tricky to use here but calling withAggregate works.
Warehouse::withAggregate(
'sales as total_income',
'sum(case when status = 1 then price * quantity when status = 2 then price * quantity * -1 else 0 end)'
)->get()

I honestly would go the route below:
Obviously my solution would have to be modified slightly if you aren't using completely whole numbers (as in your example). The if/else can be broadened out as well if you have more then the 2 statuses.
$total_income = 0;
foreach($warehouses as $warehouse)
{
foreach($warehouse->sales as $sale)
{
if($sale->status = 1)
{
$total_income += ($sale->price * $sale->quantity);
}else{
$total_income -= ($sale->price * $sale->quantity);
}
}
}
This is a crude example of what how I would do it. It seems that each 'warehouse' has a different location ex. India vs. Malaysia. My example is more about the grand total, but you could always save the results of each different warehouse in different variables, or as a key/value pair in an array (which is how I would go).

Related

PostgreSQL - Transform an INNER JOIN query to JSON hierarchy structure for frontend processing?

I've got four tables in a PostgreSQL db.
user which holds information about a logged in user.
project which holds information about projects created.
userprojects as a joined table between users and projects (one user can belong to many projects and one project can have many users).
timesheet which is where users log their hours - has relation to user_id and project_id and people log their time and date in duration and date columns.
The timesheet table itself stores data as such:
id, user_id, date, duration, project_id
1, 1, "2019-02-01", 8, 1
2, 1, "2019-02-02", 8, 1
3, 2, "2019-02-01", 10, 1
I wish to find a nice way of returning the sum of values for each month from the timesheet table for easy frontend parsing and loading that data into a chart.
What I'm looking for is something along the lines of:
{
"users": [
{
"user_id": "1",
"projects": [
{
"project_id": 1,
"sum": [
{
"august": 18
},
{
"september": 20
}
]
},
{
"project_id": 2,
"sum": [
{
"august": 25
},
{
"september": 10
}
]
}
]
},
{
"user_id": "2",
"projects": [
{
"project_id": 2,
"sum": [
{
"august": 40
},
{
"september": 100
}
]
},
{
"project_id": 3,
"sum": [
{
"august": 30
},
{
"september": 25
}
]
}
]
},
]
}
I've found a neat query which kinda structures the data a bit, but still not ideally:
SELECT
project.name,
to_char(date_trunc('month', date), 'YYYY') AS year,
to_char(date_trunc('month', date), 'Mon') AS month,
to_char(date_trunc('month', date), 'MM') AS month_number,
sum(duration) AS monthly_sum
FROM timesheet INNER JOIN project ON timesheet.project_id = project.id
GROUP BY year, month, month_number, project.name
This query simply returns a table that looks something like:
name: year: month: month_number: monthly_sum
Project XX 2019 Aug 08 10,
Project YY 2019 Aug 08 30,
Project YY 2019 Sep 09 20
How would you guys go around formatting the timesheet table so I can easily display the summed value on a month by month basis?

how to implement sub select with where condition in sequelize

I have these tables:
products
stores
produuctProperties
with this structure
[
"products" :
{
"id": 1,
"orginalName": "146153-0100 ",
"title": null,
"stores": [
{
"id": 1,
"stock": 100,
"minOQ": 1,
"maxOQ": 0
},
{
"id": 2,
"stock": 100,
"minOQ": 1,
"maxOQ": 0,
}
],
"productproperties": [
{
"id": 1,
"productId": 1,
"propertyId": 8,
"propertyOptionId": 5
},
{
"id": 2,
"productId": 1,
"propertyId": 9,
"propertyOptionId": 11
},
{
"id": 3,
"productId": 1,
"propertyId": 10,
"propertyOptionId": 9
}
]
}
]
I want filter my products by selected options , Suppose the selected options are 11 and 9
how to implement below sql query in Sequelize 5.6 with findAll , where and... :
select * from products as p
inner join stores as sr on sr.productId = p.id
where (select count(*) from productProperties where propertyOptionId in (11,9) and productId = p.id) >= 2
I've found that using query builder in sequelize is really confusing,
so if you're good with raw sql you could just run them on as below
if Student is you're model
then
const students = Student.query('Select * from students');

Flatten nested JSON structure in PostgreSQL

I'm trying to write a Postgres query that will output my json data in a particular format.
JSON data structure
{
user_id: 123,
data: {
skills: {
"skill_1": {
"title": "skill_1",
"rating": 4,
"description": 'description text'
},
"skill_2": {
"title": "skill_2",
"rating": 2,
"description": 'description text'
},
"skill_3": {
"title": "skill_3",
"rating": 5,
"description": 'description text'
},
...
}
}
}
This is how I need the data to be formatted in the end:
[
{
user_id: 123,
skill_1: 4,
skill_2: 2,
skill_3: 5,
...
},
{
user_id: 456,
skill_1: 1,
skill_2: 3,
skill_3: 4,
...
}
]
So far I'm working with a query that looks like this:
SELECT
user_id,
data#>>'{skills, "skill_1", rating}' AS "skill_1",
data#>>'{skills, "skill_2", rating}' AS "skill_2",
data#>>'{skills, "skill_3", rating}' AS "skill_3"
FROM some_table
There has to be a better way to go about writing my query. There are 400+ rows and 70+ skills. My above query is a little crazy. Any guidance or help would be greatly appreciated.
Some things to note:
Users rated themselves on 70+ skills
Each skill object has the same structure
Each user rated themselves on the exact same set of skills
db<>fiddle
I expanded your test data to (note the array around all users):
[{
"user_id": 123,
"data": {
"skills": {
"skill_1": {
"title": "skill_1",
"rating": 4,
"description": "description text"
},
"skill_2": {
"title": "skill_2",
"rating": 2,
"description": "description text"
},
"skill_3": {
"title": "skill_3",
"rating": 5,
"description": "description text"
}
}
}
},
{
"user_id": 456,
"data": {
"skills": {
"skill_1": {
"title": "skill_1",
"rating": 1,
"description": "description text"
},
"skill_2": {
"title": "skill_2",
"rating": 3,
"description": "description text"
},
"skill_3": {
"title": "skill_3",
"rating": 4,
"description": "description text"
}
}
}
}]
The query:
SELECT
jsonb_pretty(jsonb_agg(user_id || skills)) -- E
FROM (
SELECT
json_build_object('user_id', user_id)::jsonb as user_id, -- D
json_object_agg(skill_title, skills -> skill_title -> 'rating')::jsonb as skills
FROM (
SELECT
user_id,
json_object_keys(skills) as skill_title, -- C
skills
FROM (
SELECT
(datasets -> 'user_id')::text as user_id,
datasets -> 'data' -> 'skills' as skills -- B
FROM (
SELECT
json_array_elements(json) as datasets -- A
FROM (
SELECT '/* the JSON data; see db<>fiddle */'::json
)s
)s
)s
)s
GROUP BY user_id
ORDER BY user_id
)s
A Make all array elements ({user_id: '42', data: {...}}) one row each
B First column safe the user_id. The cast to text ist necessary for the GROUP BY later which cannot group JSON output. For the second column extract the skills data of the user
C Extract the skill titles for using them as keys in (D.1).
D.1 skills -> skill_title -> 'rating' extracts the rating value from each skill
D.2 json_object_agg aggregates the skill_titles and each corresponding rating value into one JSON object; grouped by the user_id
D.3 json_build_object makes the user_id a JSON object again
E.1 user_id || skills aggregates the two json object into one
E.2 jsonb_agg aggregates these json objects into an array
E.3 jsonb_pretty makes the result looking pretty.
Result:
[{
"skill_1": 4,
"skill_2": 2,
"skill_3": 5,
"user_id": "123"
},
{
"skill_1": 1,
"skill_2": 3,
"skill_3": 4,
"skill_4": 42,
"user_id": "456"
}]

MySQL Divide Derived Columns

How can I divide to generated columns in a MySQL select? I have two database, one with questions and one with attempts. I want to pull up the attempt data for a specific question with the number of attempts, incorrect_attempts, and correct_attempts. Then I want to divide the correct attempts by the number of attempts (preferably if the attempts is greater than 0).
Here is an example query, but it does not work:
SELECT SUM(CASE WHEN qa.id > 0 THEN 1 ELSE 0 END) attempts,
SUM(CASE WHEN qa.correct = 1 THEN 1 ELSE 0 END) correct_attempts,
SUM(CASE WHEN qa.correct = 0 THEN 1 ELSE 0 END) incorrect_attempts,
(100 * correct_attempts / attempts) percentage
FROM test_questions tq
LEFT JOIN question_attempts qa ON qa.question_id = tq.id
GROUP BY id
Also, if I can get this to work, what function do I use to return the percentage to two decimal points?
Here's some example data:
{
"table": "question_attempts",
"rows":
[
{
"id": 1,
"question_id": 1,
"user_id": 8,
"correct": 1,
"created_at": "2017-01-13 12:17:42"
},
{
"id": 2,
"question_id": 1,
"user_id": 8,
"correct": 0,
"created_at": "2017-01-13 12:17:32"
}
],
"table": "test_questions",
"rows":
[
{
"id": 1,
"question": "..."
}
]
}
The result I want should look like the following:
{
"rows":
[
{
"attempts": 2,
"correct_attempts": 1,
"incorrect_attempts": 1,
"percentage": 50.00,
}
]
}

Postgres PLpgSQL JSON SUM

I'm trying to calculate the sum of some JSON values in PLpgSQL (Postgres v9.5.5) but am stuck on the logic.
For this data set:
{
clientOrderId: 'OR836374647',
status: 'PENDING',
clientId: '583b52ede4b1a3668ba0dfff',
sharerId: '583b249417329b5b737ad3ee',
buyerId: 'abcd12345678',
buyerEmail: 'test#test.com',
lineItems: [{
name: faker.commerce.productName(),
description: faker.commerce.department(),
category: 'test',
sku: faker.random.alphaNumeric(),
quantity: 3
price: 40
status: 'PENDING'
}, {
name: faker.commerce.productName(),
description: faker.commerce.department(),
category: 'test',
sku: faker.random.alphaNumeric(),
quantity: 2,
price: 30,
status: 'PENDING'
}
I am trying to get the subtotal of all the lineItems for each row (i.e. quantity * price for each line item, then the sum of these values for the row). So for the above example, the returned value should be 180.
I got this far, but this is returning the totals for all lineItems in the table, not grouped by row.
WITH line_items AS (SELECT jsonb_array_elements(line_items) as line_items FROM public.order),
line_item_totals AS (SELECT line_items->>'quantity' AS quantity, line_items->>'price' AS price FROM line_items)
SELECT (quantity::int * price::numeric) AS sub_total FROM line_item_totals;
I'm sure the fix is simple but I'm not sure how to do this with JSON fields.
Please always include Postgres version you are using. It also looks like your JSON is incorrect. Below is an example of how you can accomplish this with json type and valid json document.
with t(v) as ( VALUES
('{
"clientOrderId": "OR836374647",
"status": "PENDING",
"clientId": "583b52ede4b1a3668ba0dfff",
"sharerId": "583b249417329b5b737ad3ee",
"buyerId": "abcd12345678",
"buyerEmail": "test#test.com",
"lineItems": [{
"name": "name1",
"description": "desc1",
"category": "test",
"sku": "sku1",
"quantity": 3,
"price": 40,
"status": "PENDING"
},
{
"name": "name2",
"description": "desc2",
"category": "test",
"sku": "sku2",
"quantity": 2,
"price": 30,
"status": "PENDING"
}]
}'::JSON)
)
SELECT
v->>'clientOrderId' cId,
sum((item->>'price')::INTEGER * (item->>'quantity')::INTEGER) subtotal
FROM
t,
json_array_elements(v->'lineItems') item
GROUP BY cId;
Result:
cid | subtotal
-------------+----------
OR836374647 | 180
(1 row)