MySQL Divide Derived Columns - mysql

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,
}
]
}

Related

Select from mysql array of objects with integer number and value null or source to file without duplicates

Let's say I have a table with rows like number, image. But image is not mandatory, It can be null and when I'm selecting I want to prioritize the row with image over the one with null so i could get clean array with only one row per number.
SELECT DISTINCT number, image FROM table ORDER BY number ASC
What's now with SELECT DISTINCT:
[
{
"number": 1,
"image": null
},
{
"number": 1,
"image": "https://example.com/image1.png"
},
{
"number": 2,
"image": null
},
{
"number": 2,
"image": "https://example.com/image2.png"
},
{
"number": 3,
"image": "https://example.com/image3.png"
},
{
"number": 3,
"image": null
},
{
"number": 4,
"image": null
}
]
What I want to get:
[
{
"number": 1,
"image": "https://example.com/image1.png"
},
{
"number": 2,
"image": "https://example.com/image2.png"
},
{
"number": 3,
"image": "https://example.com/image3.png"
},
{
"number": 4,
"image": null
}
]
Try this:
SELECT number, image FROM table ORDER BY ISNULL(LEFT(image,0));

Laravel calculate sum of two columns with a condition

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).

How to generate nested nth level JSON object in T-SQL?

I have below data
against below query
declare #t table
(
Id int identity,
name varchar(50),
rootid int,
level int
);
insert into #t(name, rootid, level)
values
('Home', 0, 0)
,('Transaction', 0, 0)
, ('Settings', 0, 0)
,('Purchase Request', 2, 1)
,('Purchase Order', 2, 1)
,('Inventory', 2, 1)
,('Payment Advice', 2, 1)
,('Setup', 3, 1)
,('Budget', 3, 1)
,('CRC', 3, 1)
,('Create PR', 4, 3);
select * from #t;
Desire output:
[{
"Id": 1,
"name": "Home",
"rootid": 0,
"level": 0
}, {
"Id": 2,
"name": "Transaction",
"rootid": 0,
"level": 0,
"children": [{
"Id": 4,
"name": "Purchase Request",
"rootid": 2,
"level": 1,
"children": [{
"Id": 11,
"name": "Create PR",
"rootid": 4,
"level": 3
}]
}, {
"Id": 5,
"name": "Purchase Order",
"rootid": 2,
"level": 1
}, {
"Id": 6,
"name": "Inventory",
"rootid": 2,
"level": 1
}, {
"Id": 7,
"name": "Payment Advice",
"rootid": 2,
"level": 1
}]
}, {
"Id": 3,
"name": "Settings",
"rootid": 0,
"level": 0,
"children": [{
"Id": 8,
"name": "Setup",
"rootid": 3,
"level": 1
}, {
"Id": 9,
"name": "Budget",
"rootid": 3,
"level": 1
}, {
"Id": 10,
"name": "CRC",
"rootid": 3,
"level": 1
}]
}]
Also Tried #Iptr answer:
;WITH result (id, name, rootId, parent, Level) AS
(
SELECT id,
name,
RootId,
Id as Parent,
0 as Level
FROM #t
WHERE RootId= 0
UNION ALL
SELECT t.id,
t.Name,
t.RootId,
r.Parent,
r.Level + 1
FROM #t t
INNER JOIN result r ON r.id = t.RootId
)
SELECT t.*, json_query(nullif(c.children, '[{}]')) as children
FROM #t as t
outer apply (
select
(
select r.*
from result as r
where r.parent = t.Id
and r.level > 0
order by r.id
for json auto
) as children
) as c
where t.level = 0
order by t.Level
for json auto;
Output
[{
"Id": 1,
"name": "Home",
"rootid": 0,
"level": 0
}, {
"Id": 2,
"name": "Transaction",
"rootid": 0,
"level": 0,
"children": [{
"id": 4,
"name": "Purchase Request",
"rootId": 2,
"parent": 2,
"Level": 1
}, {
"id": 5,
"name": "Purchase Order",
"rootId": 2,
"parent": 2,
"Level": 1
}, {
"id": 6,
"name": "Inventory",
"rootId": 2,
"parent": 2,
"Level": 1
}, {
"id": 7,
"name": "Payment Advice",
"rootId": 2,
"parent": 2,
"Level": 1
}, {
"id": 11,
"name": "Create PR",
"rootId": 4,
"parent": 2,
"Level": 2
}]
}, {
"Id": 3,
"name": "Settings",
"rootid": 0,
"level": 0,
"children": [{
"id": 8,
"name": "Setup",
"rootId": 3,
"parent": 3,
"Level": 1
}, {
"id": 9,
"name": "Budget",
"rootId": 3,
"parent": 3,
"Level": 1
}, {
"id": 10,
"name": "CRC",
"rootId": 3,
"parent": 3,
"Level": 1
}]
}]
Above query is not returning nth json child objects, let say if I have nth level of menu items, Parent have multiple Childs and Childs have multiple Childs like treeview.
Tried #Naveen Arora answer:
select ID,name,'' as id,'' as name from Navigations where id not in (select rootid from Navigations) and rootid=0
union
select B.id,B.name,A.id,A.name from Navigations A join Navigations B on A.rootid=B.id
FOR JSON AUTO;
But output
[{
"ID": 1,
"name": "Home",
"id": 0,
"name": ""
}, {
"ID": 2,
"name": "Transaction",
"id": 4,
"name": "Create PR"
}, {
"ID": 2,
"name": "Transaction",
"id": 5,
"name": "Generate PO"
}, {
"ID": 2,
"name": "Transaction",
"id": 6,
"name": "Create Receipt"
}, {
"ID": 2,
"name": "Transaction",
"id": 7,
"name": "Create Issue Request"
}, {
"ID": 2,
"name": "Transaction",
"id": 8,
"name": "Create Issue Note"
}, {
"ID": 2,
"name": "Transaction",
"id": 9,
"name": "Approve Payment Advice"
}, {
"ID": 3,
"name": "Settings",
"id": 11,
"name": "Navigation Management"
}, {
"ID": 11,
"name": "Navigation Management",
"id": 12,
"name": "Navigation & Form Mapping"
}]
Above output it's not include Childs node. Like in Settings I have Navigation Management -> Navigation & Form Mapping
If the sql server version is 2016 or newer than 2016 then you can use FOR JSON PATH.
Assuming that results are stored in test table. This is just to give you an idea how you can do this, may not give you the exact output but you can change it as per your requirement.
SELECT
t.Id AS 'Id',
t.Name AS 'Name',
children = (
SELECT A.id,A.name from test A join test B on A.rootid=B.id
FOR JSON PATH
)
FROM Test t
FOR JSON PATH;
And if it is older than 2016 then you may refer this.
declare #t table
(
Id int identity,
name varchar(50),
rootid int,
level int
);
insert into #t(name, rootid, level)
values
('Home', 0, 0),('Transaction', 0, 0), ('Settings', 0, 0),
('Create PR', 2, 1), ('Generate PO', 2, 1), ('Create Receipt', 2, 1), ('Create Issue Request', 2, 1), ('Create Issue Note', 2, 1), ('Approve Payment Advice', 2, 1),
('Navigation Management', 3, 1), ('Navigation & Form Mapping', 3, 1);
select * from #t;
;WITH result (id, name, rootId, parent, Level) AS
(
SELECT id,
name,
RootId,
Id as Parent,
0 as Level
FROM #t
WHERE RootId= 0
UNION ALL
SELECT t.id,
t.Name,
t.RootId,
r.Parent,
r.Level + 1
FROM #t t
INNER JOIN result r ON r.id = t.RootId
)
SELECT t.*, json_query(nullif(c.children, '[{}]')) as children
FROM #t as t
outer apply (
select
(
select r.*
from result as r
where r.parent = t.Id
and r.level > 0
order by r.id
for json auto
) as children
) as c
where t.level = 0
order by t.Level
for json auto;
SELECT t.*, json_query(nullif(c.children, '[{}]')) as children
FROM #t as t
outer apply (
select
(
select r.*
from #t as r
where r.rootid = t.Id
and r.level > 0
order by r.id
for json auto
) as children
) as c
where t.level = 0
order by t.Level
for json auto;
My apology for late posting my answer. But I really appreciate the efforts of #Iptr and #NaveenArora answer on my post. After I do some brain storming on my case I've finally found the way to do it.
Create this function:
create function [dbo].[fnUDFCreateJSON](#currentId int)
returns varchar(max)
begin
declare #json nvarchar(max)
IF #currentId <> 0
BEGIN
set #json =
(
select [ID], [Name], CSSClass, RouteURL, json_query(dbo.fnUDFCreateJSON([ID])) as SubNavigation
from dbo.Navigations
where RootId = #currentId
for json auto
);
END
ELSE
BEGIN
set #json =
(
select [ID], [Name], CSSClass, RouteURL, '' as SubNavigation from dbo.Navigations where RootId = 0
for json auto
);
END
return #json
end
and call it by using stored procedure:
CREATE PROCEDURE [dbo].[spGetStartupNavigations]
AS
BEGIN
SELECT
(SELECT
ID, Name, CSSClass, RouteURL,
JSON_QUERY (dbo.fnUDFCreateJSON(ID)) AS SubNavigation
FROM
dbo.Navigations
WHERE
RootId = 0
FOR JSON AUTO) AS Navigation
END
That's it.

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');

Mysql / Eloquent / Laravel aggregate data returned by query in usable form for view

I have this situation:
$x = user->waist_id;
$y = user->pants_size_id;
$sizes = DB::select(DB::raw("SELECT model_id,
pants_sizes.id AS size_id,
Count(pants_sizes.id) AS Total FROM `pants_sizes`
INNER JOIN `owned_items`
ON `pants_sizes`.`id` = `owned_items`.`model_size_id`
INNER JOIN `owned_item_user`
ON `owned_items`.`id` = `owned_item_user`.`owned_item_id`
INNER JOIN `users`
ON `users`.`id` = `owned_item_user`.`user_id` WHERE `waist_id` = $x
AND `pants_size_id` = $y
AND `owned_items`.`model_id` IN ( 218, 219 ) GROUP BY `model_id`,
`pants_sizes`.`id` "))
return $sizes;
with this query I am joining some tables to get the sizes of a specific pants model owned by users based on same attributes (example waist and pants_size).
this returns the data in this form:
[
{
"model_id": 218,
"size_id": 4,
"Total": 3
},
{
"model_id": 218,
"size_id": 5,
"Total": 7
},
{
"model_id": 219,
"size_id": 4,
"Total": 3
},
{
"model_id": 219,
"size_id": 5,
"Total": 7
}
]
what I need is the data to be returned like this instead:
[
{
"model_id": 218,
"size_id": 4,
"Total_size_id_4": 3
"size_id": 5,
"Total_size_id_5": 7
"Total": 10
},
"model_id": 219,
"size_id": 4,
"Total_size_id_4": 3
"size_id": 5,
"Total_size_id_5": 7
"Total": 10
},
]
or in a way that I can use to produce statistics in the view, example:
[
{
"model_id": 218,
"4": "30%",
"5": "70%",
"Total": 10
},
"model_id": 219,
"4": "30%",
"5": "70%",
"Total": 10
},
]
"model 218 is owned by 10 users, 30% has size 4 and 70% has size 5"
Can this be done modifying the above query? with some group concat and sum stuff maybe?