Translating monad composition to SQL - mysql

I'm working on a language integrated query library in Scala (http://github.com/getquill/quill) and there's one type of monad composition that I'm struggling to generate the correspondent SQL query for.
It's possible to generate queries for these cases:
t1.flatMap(a => t2.filter(b => b.s == a.s).map(b => b.s))
SELECT t2.s FROM t1, t2 WHERE t2.s = t1.s
t1.flatMap(a => t2.map(b => b.s).take(10))
SELECT x.s FROM t1, (SELECT * FROM t2 LIMIT 10) x
But I can't figure out how to express this other one:
t1.flatMap(a => t2.filter(b => b.s == a.s).map(b => b.s).take(10))
Is it possible? The question also could be phrased as: is there a way to express this kind of data dependency in monadic compositions using applicative joins in SQL?
I'm looking for a generic solution so it could be used for other compositions like these ones:
t1.flatMap(a => t2.filter(b => b.s == a.s).sortBy(b => b.s % a.s).map(b => b.s).take(10))
t1.flatMap(a => t2.filter(b => b.s == a.s).map(b => b.s).take(10).flatMap(b => t3.filter(c => c.s == b.s/a.s))
I'm working on dialects for MySQL, Postgres and H2.

Once you need to filter the inner set, by the existence in the outer you need to push the join down. Something like this, maybe:
SELECT *
FROM t1, (
SELECT t2.s
FROM t2, t1 AS t1_inner
WHERE t1_inner.s = t2.s
LIMIT 10
)
Or, alternatively:
SELECT *
FROM t1, (
SELECT t2.s
FROM t2
WHERE EXISTS (SELECT * FROM t1 t1_inner WHERE t1_inner.s = t2.s)
LIMIT 10
)

Related

combine two queries as one without looping mysql

how to join this in single query any help to combine these two queries as one without looping,
$today_date = mktime(0, 0, 0, $mon, $day-1, $year);
SELECT * FROM (`lead_follow_up`) LEFT JOIN `leads` ON `leads`.`id` = `lead_follow_up`.`lead_id` WHERE `date` <= $today_date GROUP BY `lead_follow_up`.`lead_id` ORDER BY `lead_follow_up`.`date` DESC
from the above query i get array $previou
$previou= Array
(
[0] => stdClass Object
(
[id] => 1
[lead_id] => 75943
[date] => 1438930800
[updated_on] => 1438884890
)
[1] => stdClass Object
(
[id] => 2
[lead_id] => 75943
[date] => 1416459600
[updated_on] => 1415901523
),
[2] => stdClass Object
(
[id] => 3
[lead_id] => 75943
[date] => 1416459600
[updated_on] => 1415901523
),....etc
);
foreach($previou as $key => $p):
$q = "SELECT `id` FROM (`lead_follow_up`) WHERE `lead_id` = '".$p->id."' AND `date` > '".$p->date."' ORDER BY `updated_on` DESC ";
if(!$this->db->query($q)){
$previouData[$key] = $p;
$pCount++;
}
endforeach;
how to join this in single query any help to combine these two queries as one without looping,
Your queries don't make much sense. For a start your first query has a GROUP BY lead_follow_up.lead_id but no aggregate functions. So in MySQL that will return one row for each value of lead_id (which row it returns is not defined).
Yet your array of sample data has multiple rows per lead_id so cannot have come from the query.
You are also LEFT OUTER JOINing the leads table, yet it doesn't seem to make sense to have a lead_follow_up which doesn't relate to a lead. As such you may as well use an INNER JOIN.
I am going to assume that what you want is a list of leads / lead_follow_ups and for each one a couple of all the follow ups after that particular follow up. That would give you something like this (making loads of assumptions as I do not know your table structure):-
SELECT leads.id AS lead_id,
lead_follow_up.id
lead_follow_up.`date`,
lead_follow_up.updated_on,
COUNT(lead_follow_up_future.id) AS future_lead_count
FROM leads
INNER JOIN lead_follow_up ON leads.id = lead_follow_up.lead_id
LEFT OUTER JOIN lead_follow_up AS lead_follow_up_future ON leads.id = lead_follow_up.lead_id AND lead_follow_up_future.`date` > lead_follow_up.`date`
WHERE lead_follow_up.`date` <= $today_date
GROUP BY leads.id AS lead_id,
lead_follow_up.id
lead_follow_up.`date`,
lead_follow_up.updated_on
ORDER BY lead_follow_up.date DESC

cake php how do a good query

I have a problem, i am noob with cakePHP and i use cakePHP 1.3 and i have a query with a lot subquerys and try to convert this to queryBuilder of cake using find sentences or things like this:
My query is the next-one:
SELECT
`PbFeedback`.`id`,
`PbFeedback`.`createdby`,
`PbFeedback`.`created`,
`PbFeedback`.`msg`,
`Usuario`.`name`,
`PbFeedback`.`tipo`,
COUNT(IF(PbFeedback.msg = 0, 1, 0))AS totalMsg,
`Entidad`.`nombre`
,UltimoMensaje.* , #Subconsulta
MensajeNuevo.* #Subconsulta
FROM
# A A
`eon_feedback` AS `PbFeedback`
LEFT JOIN
# B B
`eon_sys_usuarios` AS `Usuario` ON(`PbFeedback`.`createdby` = `Usuario`.`id`)
LEFT JOIN `eon_entidades` AS `Entidad` ON(
`PbFeedback`.`entidad_id` = `Entidad`.`id`
)
LEFT JOIN (SELECT
`F`.`createdby`,
`F`.`created`,
`F`.`msg`,
`F`.`tipo`
FROM eon_feedback AS `F`
GROUP BY `F`.`createdby`
ORDER BY F.created DESC
) AS UltimoMensaje ON (UltimoMensaje.createdby = `PbFeedback`.`createdby`)
LEFT JOIN (
SELECT
F.createdby AS usuario_id,
COUNT(*) AS `count`
FROM
`eon_feedback` AS `F`
WHERE `F`.`status` = 0
GROUP BY F.createdby
) AS MensajeNuevo ON MensajeNuevo.usuario_id = PbFeedback.createdby
WHERE
`PbFeedback`.`usuario_id` = 0
GROUP BY
`PbFeedback`.`createdby`
ORDER BY
`PbFeedback`.`createdby` ASC
LIMIT 0,
30 ;
Thanks ;)
I would suggest you look into the ContainableBehavior:
http://book.cakephp.org/1.3/en/The-Manual/Core-Behaviors/Containable.html
Containable allows you to easily build complex queries, for example:
$this->PbFeedback->find('all', array(
'contain' => array (
'Usuario',
'UltimoMensaje ',
'eon_feedback' => array (
'fields' => array ('created','msg','tipo'),
'conditions' => array ('eon_feedback.status =' => '0')
)
),
'limit' => 30
);

SQL left join - limit number of rows returned

I have a working SQL statement, but there is one issue within it I can't solve.
When I left join my table sites_photos there can be multiple matches on sp.sites_id = s.id, but I want the table to only return 1. Is this possible.
SELECT s.*, sp.photo
FROM sites s
LEFT JOIN sites_photos sp
ON sp.sites_id = s.id
My output: 2 times id 30, but with different photo paths, I only want 1 returned for that id, or both bundled in one array.
Array
(
[0] => Array
(
[id] => 30
[url] => www.test.nl
[name] => Aleve
[date] => 2014-08-16
[cms_active] => Y
[archive] => N
[photo] => 2014080812365920120214103601number_1.jpg
)
[1] => Array
(
[id] => 30
[url] => www.test.nl
[name] => Aleve
[date] => 2014-08-16
[cms_active] => Y
[archive] => N
[photo] => 20140811021102news.jpg
)
)
You can do so,by using GROUP_CONCAT which will concatenate all the photos per site by and produces comma separated list of photos then you can use SUBSTRING_INDEX over result of GROUP_CONCAT to pick one photo,you can also add the criteria of order by in GROUP_CONCAT as GROUP_CONCAT(sp.photo ORDER BY sp.id DESC)
SELECT s.*, SUBSTRING_INDEX(GROUP_CONCAT(sp.photo),',',1) photo
FROM sites s
LEFT JOIN sites_photos sp
ON sp.sites_id = s.id
GROUP BY s.id

CakePHP, NOT IN or excluding JOIN?

the tables are:
units (id,...) // approx' 10,000 units
contracts(id, unit_id, active, ...) // approx 50,000 records
I want to get all the units, that have no contract attached to them (and contracts.active=true).
My ideas are:
Using NOT IN:
select * from units
where id NOT IN(select unit_id from contracts where contracts.active = true)
Or:
select * from units u
left join contracts c
on c.unit_id = u.id
where c.unit_id is null
and, if there is a native way to do it in cake, please show me the light :)
thanks
Depending on what your other joins are, the NOT IN could give you bad performance. I would suggest the following SQL query:
SELECT * FROM units AS u
LEFT JOIN contracts AS c
ON (c.unit_id = u.id AND c.active = 1)
WHERE c.id IS NULL
According to the cakephp documentation:
Cake can also check for null fields. In this example, the query will return records where the post title is not null:
array ("NOT" => array (
"Post.title" => null
)
)
So depending on how your models are setup, this may work for you:
$joins = array(('table' => 'contracts',
'alias' => 'Contracts',
'type' => 'LEFT',
'conditions' => array('Contracts.active' => 0)));
$conditions = array('Contracts.id' => NULL);
$units = $this->Units->find('all', array('joins' => $joins, 'conditions' => $conditions));

Linq to SQL: how to aggregate without a group by?

I am searching for the Linq-to-SQL equivalent to this query:
SELECT
[cnt]=COUNT(*),
[colB]=SUM(colB),
[colC]=SUM(colC),
[colD]=SUM(colD)
FROM myTable
This is an aggregate without a group by. I can't seem to find any way to do this, short of issuing four separate queries (one Count and three Sum). Any ideas?
This is what I found seems like you still have to do a group by...can just use constant:
var orderTotals =
from ord in dc.Orders
group ord by 1 into og
select new
{
prop1 = og.Sum(item=> item.Col1),
prop2 = og.Sum(item => item.Col2),
prop3 = og.Count(item => item.Col3)
};
This produces the following SQL, which is not optimal, but works:
SELECT SUM([Col1]) as [prop1], SUM([Col2]) as [prop2], COUNT(*) AS [prop3]
FROM (
SELECT 1 AS [value], [t0].[Col1], [t0].[Col2], [t0].[Col3]
FROM [table] AS [t0]
) AS [t1]
GROUP BY [t1].[value]
You can do the same query using Lambda expression as follows:
var orderTotals = db.Orders
.GroupBy( i => 1)
.Select( g => new
{
cnt = g.Count(),
ScolB = g.Sum(item => item.ColB),
ScolC = g.Sum(item => item.ColC)
});