Doctrine 2 ManyToOne with multiple joinColumns - mapping

I'm trying to select the matching row in the product_item_sortorder table based on a productId and toolboxItemId from the product_item table.
In normal SQL that would be for a given productId:
SELECT pi.*, pis.* FROM product_item pi
LEFT JOIN product_item_sortorder pis
ON pi.productId = pis.productId
AND pi.toolboxItemId = pis.toolboxItemId
WHERE pi.productId = 6
I wrote the DQL for it as followed:
$this->_em->createQuery(
'SELECT pi
FROM Entities\ProductItem pi
LEFT JOIN pi.sequence s
WHERE pi.product = ?1'
);
Then I get following SQL if I output the $query->getSQL():
SELECT p0_.id AS id0, p0_.productId AS productId1, p0_.priceGroupId AS priceGroupId2, p0_.toolboxItemId AS toolboxItemId3, p0_.levelId AS levelId4, p0_.parentId AS parentId5, p0_.productId AS productId6, p0_.toolboxItemId AS toolboxItemId7 FROM product_item p0_ LEFT JOIN product_item_sortorder p1_ ON p0_.productId = p1_. AND p0_.toolboxItemId = p1_. WHERE p0_.productId = ? ORDER BY p0_.id ASC
As you can see the referencedColumnNames are not found:
LEFT JOIN product_item_sortorder p1_ ON p0_.productId = p1_. AND p0_.toolboxItemId = p1_.
Details of the product_item table:
+-----+-----------+---------------+
| id | productId | toolboxItemId |
+-----+-----------+---------------+
| 467 | 1 | 3 |
| 468 | 1 | 10 |
| 469 | 1 | 20 |
| 470 | 1 | 4 |
| 471 | 1 | 10 |
+-----+-----------+---------------+
Details of the product_item_sortorder table:
+-----+-----------+---------------+----------+
| id | productId | toolboxItemId | sequence |
+-----+-----------+---------------+----------+
| 452 | 1 | 3 | 1 |
| 457 | 1 | 4 | 6 |
| 474 | 1 | 20 | 4 |
+-----+-----------+---------------+----------+
ProductItem Entity
<?php
/**
* #Entity(repositoryClass="Repositories\ProductItem")
* #Table(name="product_item")
*/
class ProductItem
{
...
/**
* #ManyToOne(targetEntity="ProductItemSortorder")
* #JoinColumns({
* #JoinColumn(name="productId", referencedColumnName="productId"),
* #JoinColumn(name="toolboxItemId", referencedColumnName="toolboxItemId")
* })
*/
protected $sequence;
...
?>
ProductItemSortOrder Entity
<?php
/**
* #Entity(repositoryClass="Repositories\ProductItemSortorder")
* #Table(name="product_item_sortorder")
*/
class ProductItemSortorder
{
...
/**
* #ManyToOne(targetEntity="Product")
* #JoinColumn(name="productId", referencedColumnName="id")
*/
protected $product;
/**
* #ManyToOne(targetEntity="ToolboxItem")
* #JoinColumn(name="toolboxItemId", referencedColumnName="id")
*/
protected $toolboxItem;
...
}
?>

Your mappings are seriously wrong. You are using ManyToOne on both ends, how is this possible? You have both associations defined as "owning"-side, no mapped-by or inversed-by (See Association Mappings chapter). And you are using join columns of one association to map to many fields in another entity. I suppose you want to do something else, can you describe exactly your use-case?

How you would map your example in YAML (since #Hernan Rajchert's example is only in annotations):
ProductItem:
type: entity
manyToOne:
sequence:
targetEntity: ProductItemSortorder
joinColumns:
productId:
referencedColumnName: productId
toolboxItemId:
referencedColumnName: toolboxItemId

Related

How To Distinct OrderSymbol() In MQL4

How to distinct OrderSymbol() in MQL4?
I have data:
Symbol | Type | Size
GBPUSD | Buy | 1.5
GBPUSD | Buy | 0.5
EURUSD | Sell | 1
USDJPY | Buy | 2
I want the result:
GBPUSD
EURUSD
USDJY
Thanks
No direct way. Collect the data and put into array, maybe sort after every insert in order to use binary search (if list is large). Here is an example of parsing current orders.
#include<Arrays\ArrayString.mqh>
ArrayString *list = listOfUniqueSymbols();
ArrayString* listOfUniqueSymbols()
{
CArrayString *result = new CArrayString();
for(int i=OrdersTotal()-1;i>=0;i--)
{
if(!OrderSelect(i,SELECT_BY_POS))continue;
const string symbol=OrderSymbol();
if(result.Search(symbol)==-1)
{
result.Add(symbol);
result.Sort();
}
}
return result;
}

Query with postgresql

Here below some sample 3 data, using PostgreSQL and rails
Stock
id: 42324
name: 'n1'
stock_items
id: 57889359
stock_id: 42324
check_id: 14123
turn: 5
mock_id: 57889357
id: 57889360
stock_id: 42324
check_id: 14141
turn: 3
mock_id: 0
Stock
id: 42325
name: 'n1'
stock_items
id: 57889361
stock_id: 42325
check_id: 19499
turn: 5
mock_id: 57889359
id: 57889362
stock_id: 42325
check_id: 19500
turn: 3
mock_id: 0
Here i have stock table and stock_items table i am trying to take the result like
if mock_id is 0 then get the check_id else other check_id whose mock_id is not zero.
So i tried one query
SELECT
check_id1,
CASE
WHEN stock_items.mock_id = 0 THEN stock_items.check_id
ELSE stock_items.check_id
END as check_id2
FROM
stock_items
INNER JOIN stocks on stocks.id = stock_items.stock_id ;
but the above query fails, but i need it like below, any suggestions?
check_id1 (mock_id=0) | check_id2 (mock_id !=0)
----------------------+-----------------------
14141 | 14123
19500 | 19499
CASE statement doesn't work like you think. You can read it here https://www.postgresql.org/docs/8.1/static/functions-conditional.html
Your query shoud look like this
SELECT s.check_id1, s2.check_id1 FROM stock_items s, (SELECT * FROM stock_items WHERE mock_id <> 0) s2 WHERE s.stock_id = s2.stock_id
What you're trying to do is basically a PIVOT. You should actually use two CASE, within an aggregation function, and having a GROUP BY (and an ORDER BY to get the order you gave):
SELECT
stock_id,
max(CASE when mock_id =0 then check_id END) AS "check_id1 (mock_id=0)",
max(CASE when mock_id<>0 then check_id END) AS "check_id2 (mock_id!=0)"
FROM
stock_items
INNER JOIN stocks on stocks.id = stock_items.stock_id
GROUP BY
stock_id
ORDER BY
stock_id;
stock_id | check_id1 (mock_id=0) | check_id2 (mock_id!=0)
-------: | --------------------: | ---------------------:
42324 | 14141 | 14123
42325 | 19500 | 19499
NOTE: I've added the stock_id so that the result is easier to understand. You can omit it if you don't actually want it in your response.
You can check all the setup and test it at dbfiddle here
UPDATE
As per comments
SELECT
stock_id,
-- This will get rid of the null in array_agg
ARRAY(SELECT
e
FROM
unnest(all_check_ids_with_mock_id_0) AS e
WHERE
e IS NOT NULL
) AS all_check_ids_with_mock_id_0,
ARRAY(SELECT
e
FROM
unnest(all_check_ids_with_mock_id_non_0) AS e
WHERE
e IS NOT NULL
) AS all_check_ids_with_mock_id_non_0
FROM
(
SELECT
stock_id,
array_agg(CASE WHEN mock_id =0 THEN check_id END) AS all_check_ids_with_mock_id_0,
array_agg(CASE WHEN mock_id<>0 THEN check_id END) AS all_check_ids_with_mock_id_non_0
FROM
stock_items
INNER JOIN stocks on stocks.id = stock_items.stock_id
GROUP BY
stock_id
) AS q0
ORDER BY
stock_id;
stock_id | all_check_ids_with_mock_id_0 | all_check_ids_with_mock_id_non_0
-------: | :--------------------------- | :-------------------------------
20223028 | {48752} | {194907,19260}
20223029 | {48743} | {194945,194907}
20223030 | {48752} | {194907}
20223031 | {48752} | {194907}
dbfiddle here

how to group a date column based on date range in oracle

I have a table which contains a feedback about a product.It has feedback type (positive ,negative) which is a text column, date on which comments made. I need to get total count of positive ,negative feedback for particular time period . For example if the date range is 30 days, I need to get total count of positive ,negative feedback for 4 weeks , if the date range is 6 months , I need to get total count of positive ,negative feedback for each month. How to group the count based on date.
+------+------+----------+----------+---------------+--+--+--+
| Slno | User | Comments | type | commenteddate | | | |
+------+------+----------+----------+---------------+--+--+--+
| 1 | a | aaaa | positive | 22-jun-2016 | | | |
| 2 | b | bbb | positive | 1-jun-2016 | | | |
| 3 | c | qqq | negative | 2-jun-2016 | | | |
| 4 | d | ccc | neutral | 3-may-2016 | | | |
| 5 | e | www | positive | 2-apr-2016 | | | |
| 6 | f | s | negative | 11-nov-2015 | | | |
+------+------+----------+----------+---------------+--+--+--+
Query i tried is
SELECT type, to_char(commenteddate,'DD-MM-YYYY'), Count(type) FROM comments GROUP BY type, to_char(commenteddate,'DD-MM-YYYY');
Here's a kick at the can...
Assumptions:
you want to be able to switch the groupings to weekly or monthly only
the start of the first period will be the first date in the feedback data; intervals will be calculated from this initial date
output will show feedback value, time period, count
time periods will not overlap so periods will be x -> x + interval - 1 day
time of day is not important (time for commented dates is always 00:00:00)
First, create some sample data (100 rows):
drop table product_feedback purge;
create table product_feedback
as
select rownum as slno
, chr(65 + MOD(rownum, 26)) as userid
, lpad(chr(65 + MOD(rownum, 26)), 5, chr(65 + MOD(rownum, 26))) as comments
, trunc(sysdate) + rownum + trunc(dbms_random.value * 10) as commented_date
, case mod(rownum * TRUNC(dbms_random.value * 10), 3)
when 0 then 'positive'
when 1 then 'negative'
when 2 then 'neutral' end as feedback
from dual
connect by level <= 100
;
Here's what my sample data looks like:
select *
from product_feedback
;
SLNO USERID COMMENTS COMMENTED_DATE FEEDBACK
1 B BBBBB 2016-08-06 neutral
2 C CCCCC 2016-08-06 negative
3 D DDDDD 2016-08-14 positive
4 E EEEEE 2016-08-16 negative
5 F FFFFF 2016-08-09 negative
6 G GGGGG 2016-08-14 positive
7 H HHHHH 2016-08-17 positive
8 I IIIII 2016-08-18 positive
9 J JJJJJ 2016-08-12 positive
10 K KKKKK 2016-08-15 neutral
11 L LLLLL 2016-08-23 neutral
12 M MMMMM 2016-08-19 positive
13 N NNNNN 2016-08-16 neutral
...
Now for the fun part. Here's the gist:
find out what the earliest and latest commented dates are in the data
include a query where you can set the time period (to "WEEKS" or "MONTHS")
generate all of the (weekly or monthly) time periods between the min/max dates
join the product feedback to the time periods (commented date between start and end) with an outer join in case you want to see all time periods whether or not there was any feedback
group the joined result by feedback, period start, and period end, and set up a column to count one of the 3 possible feedback values
x
with
min_max_dates -- get earliest and latest feedback dates
as
(select min(commented_date) min_date, max(commented_date) max_date
from product_feedback
)
, time_period_interval
as
(select 'MONTHS' as tp_interval -- set the interval/time period here
from dual
)
, -- generate all time periods between the start date and end date
time_periods (start_of_period, end_of_period, max_date, time_period) -- recursive with clause - fun stuff!
as
(select mmd.min_date as start_of_period
, CASE WHEN tpi.tp_interval = 'WEEKS'
THEN mmd.min_date + 7
WHEN tpi.tp_interval = 'MONTHS'
THEN ADD_MONTHS(mmd.min_date, 1)
ELSE NULL
END - 1 as end_of_period
, mmd.max_date
, tpi.tp_interval as time_period
from time_period_interval tpi
cross join
min_max_dates mmd
UNION ALL
select CASE WHEN time_period = 'WEEKS'
THEN start_of_period + 7 * (ROWNUM )
WHEN time_period = 'MONTHS'
THEN ADD_MONTHS(start_of_period, ROWNUM)
ELSE NULL
END as start_of_period
, CASE WHEN time_period = 'WEEKS'
THEN start_of_period + 7 * (ROWNUM + 1)
WHEN time_period = 'MONTHS'
THEN ADD_MONTHS(start_of_period, ROWNUM + 1)
ELSE NULL
END - 1 as end_of_period
, max_date
, time_period
from time_periods
where end_of_period <= max_date
)
-- now put it all together
select pf.feedback
, tp.start_of_period
, tp.end_of_period
, count(*) as feedback_count
from time_periods tp
left outer join
product_feedback pf
on pf.commented_date between tp.start_of_period and tp.end_of_period
group by tp.start_of_period
, tp.end_of_period
, pf.feedback
order by pf.feedback
, tp.start_of_period
;
Output:
negative 2016-08-06 2016-09-05 6
negative 2016-09-06 2016-10-05 7
negative 2016-10-06 2016-11-05 8
negative 2016-11-06 2016-12-05 1
neutral 2016-08-06 2016-09-05 6
neutral 2016-09-06 2016-10-05 5
neutral 2016-10-06 2016-11-05 11
neutral 2016-11-06 2016-12-05 2
positive 2016-08-06 2016-09-05 17
positive 2016-09-06 2016-10-05 16
positive 2016-10-06 2016-11-05 15
positive 2016-11-06 2016-12-05 6
-- EDIT --
New and improved, all in one easy to use procedure. (I will assume you can configure the procedure to make use of the query in whatever way you need.) I made some changes to simplify the CASE statements in a few places and note that for whatever reason using a LEFT OUTER JOIN in the main SELECT results in an ORA-600 error for me so I switched it to INNER JOIN.
CREATE OR REPLACE PROCEDURE feedback_counts(p_days_chosen IN NUMBER, p_cursor OUT SYS_REFCURSOR)
AS
BEGIN
OPEN p_cursor FOR
with
min_max_dates -- get earliest and latest feedback dates
as
(select min(commented_date) min_date, max(commented_date) max_date
from product_feedback
)
, time_period_interval
as
(select CASE
WHEN p_days_chosen BETWEEN 1 AND 10 THEN 'DAYS'
WHEN p_days_chosen > 10 AND p_days_chosen <=31 THEN 'WEEKS'
WHEN p_days_chosen > 31 AND p_days_chosen <= 365 THEN 'MONTHS'
ELSE '3-MONTHS'
END as tp_interval -- set the interval/time period here
from dual --(SELECT p_days_chosen as days_chosen from dual)
)
, -- generate all time periods between the start date and end date
time_periods (start_of_period, end_of_period, max_date, tp_interval) -- recursive with clause - fun stuff!
as
(select mmd.min_date as start_of_period
, CASE tpi.tp_interval
WHEN 'DAYS'
THEN mmd.min_date + 1
WHEN 'WEEKS'
THEN mmd.min_date + 7
WHEN 'MONTHS'
THEN mmd.min_date + 30
WHEN '3-MONTHS'
THEN mmd.min_date + 90
ELSE NULL
END - 1 as end_of_period
, mmd.max_date
, tpi.tp_interval
from time_period_interval tpi
cross join
min_max_dates mmd
UNION ALL
select CASE tp_interval
WHEN 'DAYS'
THEN start_of_period + 1 * ROWNUM
WHEN 'WEEKS'
THEN start_of_period + 7 * ROWNUM
WHEN 'MONTHS'
THEN start_of_period + 30 * ROWNUM
WHEN '3-MONTHS'
THEN start_of_period + 90 * ROWNUM
ELSE NULL
END as start_of_period
, start_of_period
+ CASE tp_interval
WHEN 'DAYS'
THEN 1
WHEN 'WEEKS'
THEN 7
WHEN 'MONTHS'
THEN 30
WHEN '3-MONTHS'
THEN 90
ELSE NULL
END * (ROWNUM + 1)
- 1 as end_of_period
, max_date
, tp_interval
from time_periods
where end_of_period <= max_date
)
-- now put it all together
select pf.feedback
, tp.start_of_period
, tp.end_of_period
, count(*) as feedback_count
from time_periods tp
inner join -- currently a bug that prevents the procedure from compiling with a LEFT OUTER JOIN
product_feedback pf
on pf.commented_date between tp.start_of_period and tp.end_of_period
group by tp.start_of_period
, tp.end_of_period
, pf.feedback
order by tp.start_of_period
, pf.feedback
;
END;
Test the procedure (in something like SQLPlus or SQL Developer):
var x refcursor
exec feedback_counts(10, :x)
print :x

Doctrine2 Sortable Update Position

I am using Doctrine 2 with Symfony 2.3 and jQuery UI sortable.
I have a list of elements sortable with jQuery and the position is saved in the database through an Ajax request.
All seem to work perfectly except the data persistence... The position of the element and the other elements related to it in the database is wrong.
Example :
| ID | POSITION | TITLE
| 1 | 0 | Element 1
| 2 | 1 | Element 2
| 3 | 2 | Element 3
| 4 | 3 | Element 4
If I am moving ID 3 (position 3) to position 0, I get this result in the database:
| ID | POSITION | TITLE
| 1 | 2 | Element 1
| 2 | 2 | Element 2
| 3 | 0 | Element 3
| 4 | 4 | Element 4
I checked and the value inserted is right (0).
I am using this code to update the position:
$pyramid = $this->getDoctrine()->getRepository('MarquisWebsiteBundle:Pyramid')->find($id);
$pyramid->setPosition($position);
$em->persist($pyramid);
$em->flush();
It's working well if i am moving Element 1 from position 0 to position 1.
I am not using any SortableGroup on this table.
EDIT:
I am using StofDoctrineExtensionsBundle with the Gedmo DoctrineExtension and here is the configuration:
doctrine:
orm:
auto_generate_proxy_classes: %kernel.debug%
auto_mapping: true
mappings:
gedmo_sortable:
type: annotation
prefix: Gedmo\Sortable\Entity
dir: "%kernel.root_dir%/../vendor/gedmo/doctrine-extensions/lib/Gedmo/Sortable/Entity"
alias: GedmoSortable
is_bundle: false
gedmo_translatable:
type: annotation
prefix: Gedmo\Translatable\Entity
dir: "%kernel.root_dir%/../vendor/gedmo/doctrine-extensions/lib/Gedmo/Translatable/Entity"
alias: GedmoTranslatable
is_bundle: false
stof_doctrine_extensions:
default_locale: en_GB
translation_fallback: true
orm:
default:
sortable: true
translatable: true
And the entity (Pyramid.orm.yml):
Acme\DemoBundle\Entity\Pyramid:
type: entity
table: pyramid
fields:
id:
id: true
type: integer
unsigned: false
nullable: false
generator:
strategy: IDENTITY
position:
type: integer
unsigned: false
nullable: false
gedmo:
- sortablePosition
title:
type: string
length: 255
fixed: false
nullable: false
I don't think I need to change anything in the Pyramid.php class which looks like this:
/**
* Pyramid
*
* #ORM\Table(name="pyramid")
* #ORM\Entity
*/
class Pyramid
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #var integer
*
* #ORM\Column(name="position", type="integer", nullable=false)
*/
private $position;
/**
* #var string
*
* #ORM\Column(name="title", type="string", length=255, nullable=false)
*/
private $title;
I think you need to include the SortablePosition annotation:
/**
* #Gedmo\SortablePosition
* #ORM\Column(name="position", type="integer", nullable=false)
*/
private $position;

invert rows and cols SQLite

I'm developing and iOS game and I want to switch cols and rows
For example here is the stat's table :
StatName (STRING) | StatValue (NUMBER)
--------------------------------------
NbJoker | 12
--------------------------------------
NbPlayed | 71
--------------------------------------
NbPause | 87
--------------------------------------
I need
NbJoker | NbPlayed | NbPause
----------------------------
12 | 71 | 87
Is that possible ?
Thanks!
I do not know SQL Lite. But If the below syntax works.
It's like the same as a Transpose in any SQL.
SELECT SUM(T1) AS NBJOKER, SUM(T2) AS NBPLAYED, SUM(T3) AS NBPAUSE FROM (
SELECT STATVALUE AS T1,O AS T2,0 AS T3 FROM TABLE_X WHERE STATNAME='NBJOKER'
UNION ALL
SELECT 0, STATVALUE, 0 FROM TABLE_X WHERE STATNAME='NBLAYED'
UNION ALL
SELECT 0, 0, STATVALUE FROM TABLE_X WHERE STATNAME='NBPAUSE'
)

Resources