SQL query to get a joinned table - mysql

I have two tables that I need to join and need to get the data that I can use to plot.
Sample data for two tables are:
**table1**
mon_pjt month planned_hours
pjt1 01-10-2019 24
pjt2 01-01-2020 67
pjt3 01-02-2019 12
**table2**
date project hrs_consumed
07-12-2019 pjt1 7
09-09-2019 pjt2 3
12-10-2019 pjt1 4
01-02-2019 pjt3 5
11-10-2019 pjt1 4
Sample Output, where the actual hours are summation of column hrs_consumed in table2. Following is the sample output:
project label planned_hours actual_hours
pjt1 Oct-19 24 8
pjt1 Dec-19 0 7
pjt2 Sep-19 0 3
pjt2 Jan-20 67 0
pjt3 Feb-19 12 5
I have tried the following query but it gives error:
Select Sum(a.hrs_consumed), a.date, a.planned_hours
From (SELECT t1.date, t2.month, t1.project, t1.hrs_consumed, t2.planned_hours
from table1 t1 JOIN
table2 t2
on t2.month = t1.date
UNION
SELECT t1.date, t2.month, t1.mon_pjt, t2.hrs_consumed, t1.planned_hours
from table t1 JOIN
table2 t2
on t1.date != t2.month
)
I have tried another way also extracting two tables separately and in javascript trying to join it and sort it but that was also vain.

In Javascript, you could mimic an SQL like request.
This code takes a pipe and
selects wanted key and formats date into a comparable format,
groups by date,
gets the sum of hrs_consumed for each group,
makes a full join (with an updated data set for comparable keys/columns),
selects wanted keys,
applies a sorting.
const
pipe = (...functions) => input => functions.reduce((acc, fn) => fn(acc), input),
groupBy = key => array => array.reduce((r, o) => {
var fn = typeof key === 'function' ? key : o => o[key],
temp = r.find(([p]) => fn(o) === fn(p));
if (temp) temp.push(o);
else r.push([o]);
return r;
}, []),
sum = key => array => array.reduce((a, b) => ({ ...a, [key]: a[key] + b[key] })),
select = fn => array => array.map(fn),
fullJoin = (b, ...keys) => a => {
const iter = (array, key) => array.forEach(o => {
var k = typeof key === 'function' ? key(o) : o[key];
temp[k] = { ...(temp[k] || {}), ...o };
});
var temp = {};
iter(a, keys[0]);
iter(b, keys[1] || keys[0]);
return Object.values(temp);
},
order = keys => array => array.sort((a, b) => {
var result;
[].concat(keys).some(k => result = a[k] > b[k] || -(a[k] < b[k]));
return result
});
var table1 = [{ mon_pjt: 'pjt1', month: '2019-10', planned_hours: 24 }, { mon_pjt: 'pjt2', month: '2020-01', planned_hours: 67 }, { mon_pjt: 'pjt3', month: '2019-02', planned_hours: 12 }],
table2 = [{ date: '2019-12-07', project: 'pjt1', hrs_consumed: 7 }, { date: '2019-09-09', project: 'pjt2', hrs_consumed: 3 }, { date: '2019-10-12', project: 'pjt1', hrs_consumed: 4 }, { date: '2019-02-01', project: 'pjt3', hrs_consumed: 5 }, { date: '2019-10-11', project: 'pjt1', hrs_consumed: 4 }],
result = pipe(
select(o => ({ ...o, date: o.date.slice(0, 7) })),
groupBy('date'),
select(sum('hrs_consumed')),
fullJoin(
select
(({ mon_pjt: project, month: date, ...o }) => ({ project, date, ...o }))
(table1),
'date'
),
select(({ project, date: label, planned_hours = 0, hrs_consumed = 0 }) => ({ project, label, planned_hours, hrs_consumed })),
order(['project', 'label'])
)(table2);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

SELECT project, label,planned_hours,(planned_hours-hours_consumed) AS actual_hours
FROM(
SELECT t1.mon_pjt AS project,date_format(t1.month,'%M-%Y') AS label,
t1.planned_hours,0 AS hours_consumed
FROM table1 t1
UNION
SELECT t2.project,date_format(t2.date,'%M-%Y') AS label,0 as planned_hours,
sum(t2.hours_consumed) AS hours_consumed
FROM table1 t2
GROUP BY project)t
GROUP BY t.project
ORDER BY project

Related

Why laravel select and group by return same value

I try to select count and group with Laravel query, but they are return same value with different field.
This is my code:
$kategoris = ['NUK', 'Hubkel', 'Sta_kawin'];
foreach ($kategoris as $kategori) {
$raw[] = 'count('.$kategori.') as '.$kategori;
}
$implodeRaw = implode(', ', $raw);
$desas = DB::table('arts')
->select('arts.id', 'KDKEC', 'KDDESA', DB::raw($implodeRaw))
->where(['KDKEC' => $kodeKecamatan])
->groupBy('KDDESA')
->orderBy('KDDESA', 'ASC')
->get();
Result:
results: {
0 => {
'id': 10
'NUK': 6
'Hubkel': 6
'Sta_kawin': 6
}
1 => {
'id': 13
'NUK': 1
'Hubkel': 1
'Sta_kawin': 1
}
}
So, what's wrong with this code? I want the NUK, Hubkel, Sta_kawin return different value because the source data is different.

Fetch all records from table A where id = somvalue in B plus records which don't have id in B

I have two tables a coupons table and a coupon_city_map table.
id
coupon_code
1
OFFER20
2
OFFER10
3
OFFER50
4
OFFER40
5
OFFER90
coupon_Id
city_id
1
2
2
3
3
4
4
2
I need coupons with ids 1 4, and 5 for city_id = 2.
So It should fetch all the coupons where city_id=2 i.e. coupons with id 1 and 4
and it should also fetch coupons which don't have key in coupon_city_map i.e 5.
This is what I have tried but the query in [Op.or] is not working, and it returns all the coupons instead.
let coupons = await Coupon.findAll({
where: {
[Op.or]: [
{ '$CouponCities.city_id$': city_id },
{ '$CouponCities.coupon_id$': null },
],
...filters // other filter like is_active: true
},
include: {
model: CouponCity,
attributes: [],
},
attributes: ['id', 'coupon_code', 'discount_per', 'flat_discount', 'discount_upto', 'description', 'display'],
});
The query being generated
SELECT `Coupon`.`id`,
`Coupon`.`coupon_code`,
`Coupon`.`discount_per`,
`Coupon`.`flat_discount`,
`Coupon`.`discount_upto`,
`Coupon`.`description`,
`Coupon`.`display`
FROM `coupons` AS `Coupon`
LEFT OUTER JOIN `coupon_city_map` AS `CouponCities` ON `Coupon`.`id` = `CouponCities`.`coupon_id`
WHERE (`Coupon`.`user_id` IS NULL OR `Coupon`.`user_id` = 1)
AND `Coupon`.`is_active` = true
AND `Coupon`.`is_external` = false
AND `Coupon`.`start_date` < '2020-12-30 10:33:20'
AND `Coupon`.`expiry_date` > '2020-12-30 10:33:20';
Update
I also tried below, but still it is returning all the coupons.
let coupons = await Coupon.findAll({
// where: {
// ...filters,
// },
include: {
model: CouponCity,
required: false,
where: {
[Op.or]: [
{
zone_id: zoneId,
}, {
coupon_id: null,
},
],
},
attributes: [],
},
attributes: ['id', 'coupon_code', 'discount_per', 'flat_discount','discount_upto', 'description', 'display'],
});
...and it generates below query.
SELECT `Coupon`.`id`,
`Coupon`.`coupon_code`,
`Coupon`.`discount_per`,
`Coupon`.`flat_discount`,
`Coupon`.`discount_upto`,
`Coupon`.`description`,
`Coupon`.`display`
FROM `coupons` AS `Coupon`
LEFT OUTER JOIN `coupon_city_map` AS `CouponCities`
ON `Coupon`.`id` = `CouponCities`.`coupon_id`
AND ( `CouponCities`.`zone_id` = 1
AND `CouponCities`.`coupon_id` IS NULL )
WHERE `Coupon`.`is_active` = true
AND `Coupon`.`is_external` = false;
This is what worked for me, query is mess but it works. I am posting all the codes for better understanding for anyone interested.
Here zone is city.
{
const filters = {
start_date: {
[Op.lt]: new Date(),
},
expiry_date: {
[Op.gt]: new Date(),
},
};
if (userId) {
filters[Op.or] = [{
user_id: null,
}, {
user_id: userId,
}];
filters[Op.and] = {
[Op.or]: [
sequelize.literal('CouponZones.zone_id = 1'),
sequelize.literal('CouponZones.coupon_id IS null')
],
};
} else {
filters.user_id = null;
}
let coupons = await Coupon.findAll({
where: {
...filters,
},
include: {
model: CouponZone,
attributes: [],
},
attributes: ['id', 'coupon_code', 'discount_per', 'flat_discount', 'discount_upto', 'description', 'display'],
});
This is the query it generates.
SELECT `Coupon`.`id`,
`Coupon`.`coupon_code`,
`Coupon`.`discount_per`,
`Coupon`.`flat_discount`,
`Coupon`.`discount_upto`,
`Coupon`.`description`,
`Coupon`.`display`
FROM `coupons` AS `Coupon`
LEFT OUTER JOIN `coupon_zone_map` AS `CouponZones`
ON `Coupon`.`id` = `CouponZones`.`coupon_id`
WHERE ( `Coupon`.`user_id` IS NULL
OR `Coupon`.`user_id` = 1 )
AND ((CouponZones.zone_id = 1 OR CouponZones.coupon_id IS null))
AND `Coupon`.`is_active` = true
AND `Coupon`.`is_external` = false;
Use UNION
You can write query like below
SELECT coupons.*
FROM coupons,
coupon_city_map
WHERE coupons.id = coupon_city_map.coupon_id
AND coupon_city_map.city_id = 2
UNION
SELECT coupons.*
FROM coupons
WHERE coupons.id NOT IN(SELECT coupon_city_map.coupon_id
FROM coupon_city_map)

Laravel How Make DB raw can inside funtion

I have problem on laravel. I want to showing percentage on with eloquent, but return null value
This Is My Controller
$group_categories = Proyek::with(['modul' => function($query){
$query->select(DB::raw('((select count(*) from modul where status = 0 and deleted_at IS NULL) /
(select count(*) from modul where deleted_at IS NULL)) *
100 as count' ));
}])->get();
This Is Json return
{
id: "10",
proyek: "JuZka",
created_at: "2018-08-12 01:54:04",
updated_at: "2018-09-23 05:49:13",
modul: [ ]
},
You can use code like this:
$all_models = (new Proyek)->count();
$models = (new Proyek)->where('status', 0)->count();
$percentage = $models / $all_models * 100;
$group_categories = Proyek::wheere('modul', $percentage);

How to write subquery with multiple where in sequelize using NodeJS

I need to execute this query using sequelize.
select * from mysqlDB.songTable where
X in (SELECT X FROM movieDB4.songTable where Y like('%pencil%') and Z='title') and
Y='tam' and Z='language';
I tried like this. but it throws some invalid value[object] error. please help to resolve this query.
const tempSQL = sequelize.dialect.QueryGenerator.selectQuery('songTable',{
attributes: ['X'],
where: {
Y: {$like: '%'+text[i]},
Z: "content_title"
}})
.slice(0,-1); // to remove the ';' from the end of the SQL
User.findAll({
where: {
X: {
$in: sequelize.literal('(' + tempSQL + ')'),
$and: {Y: lang.substring(0,3),
Z: 'language'}
}
}
})
You can use sequelize.query() to execute raw queries.
Example
return this.sequelize.query(`SELECT category_id, category_name from table_categories where category_id in (SELECT DISTINCT category_id from table_authorized_service_center_details where center_id in (SELECT center_id from table_authorized_service_center where brand_id ${condition}));`).then((results) => {
if (results.length === 0) {
reply({status: true, categories: [], forceUpdate: request.pre.forceUpdate});
} else {
reply({status: true, categories: results[0], forceUpdate: request.pre.forceUpdate});
}
}).catch((err) => {
console.log(err);
reply({status: false, message: "ISE"});
});

Adjacency List to JSON graph with Postgres

I have the following schema for the tags table:
CREATE TABLE tags (
id integer NOT NULL,
name character varying(255) NOT NULL,
parent_id integer
);
I need to build a query to return the following structure (here represented as yaml for readability):
- name: Ciencia
parent_id:
id: 7
children:
- name: Química
parent_id: 7
id: 9
children: []
- name: Biología
parent_id: 7
id: 8
children:
- name: Botánica
parent_id: 8
id: 19
children: []
- name: Etología
parent_id: 8
id: 18
children: []
After some trial and error and looking for similar questions in SO, I've came up with this query:
WITH RECURSIVE tagtree AS (
SELECT tags.name, tags.parent_id, tags.id, json '[]' children
FROM tags
WHERE NOT EXISTS (SELECT 1 FROM tags tt WHERE tt.parent_id = tags.id)
UNION ALL
SELECT (tags).name, (tags).parent_id, (tags).id, array_to_json(array_agg(tagtree)) children FROM (
SELECT tags, tagtree
FROM tagtree
JOIN tags ON tagtree.parent_id = tags.id
) v
GROUP BY v.tags
)
SELECT array_to_json(array_agg(tagtree)) json
FROM tagtree
WHERE parent_id IS NULL
But it returns the following results when converted to yaml:
- name: Ciencia
parent_id:
id: 7
children:
- name: Química
parent_id: 7
id: 9
children: []
- name: Ciencia
parent_id:
id: 7
children:
- name: Biología
parent_id: 7
id: 8
children:
- name: Botánica
parent_id: 8
id: 19
children: []
- name: Etología
parent_id: 8
id: 18
children: []
The root node is duplicated.
I could merge the results to the expected result in my app code but I feel I am close and it could be done al from PG.
Here's an example with SQL Fiddle:
http://sqlfiddle.com/#!15/1846e/1/0
Expected output:
https://gist.github.com/maca/e7002eb10f36fcdbc51b
Actual output:
https://gist.github.com/maca/78e84fb7c05ff23f07f4
Here's a solution using PLV8 for your schema.
First, build a materialized path using PLSQL function and recursive CTEs.
CREATE OR REPLACE FUNCTION get_children(tag_id integer)
RETURNS json AS $$
DECLARE
result json;
BEGIN
SELECT array_to_json(array_agg(row_to_json(t))) INTO result
FROM (
WITH RECURSIVE tree AS (
SELECT id, name, ARRAY[]::INTEGER[] AS ancestors
FROM tags WHERE parent_id IS NULL
UNION ALL
SELECT tags.id, tags.name, tree.ancestors || tags.parent_id
FROM tags, tree
WHERE tags.parent_id = tree.id
) SELECT id, name, ARRAY[]::INTEGER[] AS children FROM tree WHERE $1 = tree.ancestors[array_upper(tree.ancestors,1)]
) t;
RETURN result;
END;
$$ LANGUAGE plpgsql;
Then, build the tree from the output of the above function.
CREATE OR REPLACE FUNCTION get_tree(data json) RETURNS json AS $$
var root = [];
for(var i in data) {
build_tree(data[i]['id'], data[i]['name'], data[i]['children']);
}
function build_tree(id, name, children) {
var exists = getObject(root, id);
if(exists) {
exists['children'] = children;
}
else {
root.push({'id': id, 'name': name, 'children': children});
}
}
function getObject(theObject, id) {
var result = null;
if(theObject instanceof Array) {
for(var i = 0; i < theObject.length; i++) {
result = getObject(theObject[i], id);
if (result) {
break;
}
}
}
else
{
for(var prop in theObject) {
if(prop == 'id') {
if(theObject[prop] === id) {
return theObject;
}
}
if(theObject[prop] instanceof Object || theObject[prop] instanceof Array) {
result = getObject(theObject[prop], id);
if (result) {
break;
}
}
}
}
return result;
}
return JSON.stringify(root);
$$ LANGUAGE plv8 IMMUTABLE STRICT;
This will yield the required JSON mentioned in your question. Hope that helps.
I've written a detailed post/breakdown of how this solution works here.
Try PL/Python and networkx.
Admittedly, using the following doesn't yield JSON in exactly the requested format, but the information seems to be all there and, if PL/Python is acceptable, this might be adapted into a complete answer.
CREATE OR REPLACE FUNCTION get_adjacency_data(
names text[],
ids integer[],
parent_ids integer[])
RETURNS jsonb AS
$BODY$
pairs = zip(ids, parent_ids)
import networkx as nx
import json
from networkx.readwrite import json_graph
name_dict = dict(zip(ids, names))
G=nx.DiGraph()
G.add_nodes_from(ids)
nx.set_node_attributes(G, 'name', name_dict)
G.add_edges_from(pairs)
return json.dumps(json_graph.adjacency_data(G))
$BODY$ LANGUAGE plpythonu;
WITH raw_data AS (
SELECT array_agg(name) AS names,
array_agg(parent_id) AS parent_ids,
array_agg(id) AS ids
FROM tags
WHERE parent_id IS NOT NULL)
SELECT get_adjacency_data(names, parent_ids, ids)
FROM raw_data;
i was finding same solution and may be this example could be useful for anyone
tested on Postgres 10 with table with same structure
table with columns: id, name and pid as parent_id
create or replace function get_c_tree(p_parent int8) returns setof jsonb as $$
select
case
when count(x) > 0 then jsonb_build_object('id', c.id, 'name', c.name, 'children', jsonb_agg(f.x))
else jsonb_build_object('id', c.id, 'name', c.name, 'children', null)
end
from company c left join get_c_tree(c.id) as f(x) on true
where c.pid = p_parent or (p_parent is null and c.pid is null)
group by c.id, c.name;
$$ language sql;
select jsonb_agg(get_c_tree) from get_c_tree(null::int8);