postgresql group by - mysql

This is my query in Postgresql:
SELECT
C.id, S.domen, B.name, C.source_id, ST.name
FROM "calls" C
INNER JOIN "site" S ON S.id=C.site_id
INNER JOIN "sources" ON sources.id=C.source_id
INNER JOIN "brand" B ON B.id = S.id_brand
INNER JOIN "source_types" ST ON ST.id = "sources".type_id
WHERE
("calltime" >= '2017-12-01') AND
("calltime" <= '2017-12-03') AND
(S."id_brand"='6')
ORDER BY "calltime" LIMIT 50
And I get this result:
Now I am trying to group by name(last column) this result to get result like this:
Контекстная реклама - 17
SEO-10
....
And for this I use this query:
SELECT
ST.name, count(ST.name)
FROM "calls" C
INNER JOIN "site" S ON S.id=C.site_id
INNER JOIN "sources" ON sources.id=C.source_id
INNER JOIN "brand" B ON B.id = S.id_brand
INNER JOIN "source_types" ST ON ST.id = "sources".type_id
WHERE
("calltime" >= '2017-12-01') AND
("calltime" <= '2017-12-03') AND
(S."id_brand"='6')
GROUP BY ST.name
ORDER BY count(ST.name) DESC LIMIT 50
But I am getting wrong result:
Seems like it take values from source_id column.
what am I doing wrong?

Try this, If you call group by before limit the result then group by for the entire records. So first filter then do the group by.
SELECT
name, count(name)
FROM(
SELECT
ST.name
FROM "calls" C
INNER JOIN "site" S ON S.id=C.site_id
INNER JOIN "sources" ON sources.id=C.source_id
INNER JOIN "brand" B ON B.id = S.id_brand
INNER JOIN "source_types" ST ON ST.id = "sources".type_id
WHERE
("calltime" >= '2017-12-01') AND
("calltime" <= '2017-12-03') AND
(S."id_brand"='6')
ORDER BY "calltime" LIMIT 50
) T
GROUP BY name

The LIMIT 50 in the second query is executed after the GROUP BY.
If you want to aggregate only the first 50 lines, write the LIMIT 50 into a subselect and perform the GROUP BY in the outer SELECT.

It's possible that the 49 is just a coincidence. Try:
SELECT
ST.name, count(*)
FROM "calls" C
INNER JOIN "site" S ON S.id=C.site_id
INNER JOIN "sources" ON sources.id=C.source_id
INNER JOIN "brand" B ON B.id = S.id_brand
INNER JOIN "source_types" ST ON ST.id = "sources".type_id
WHERE
("calltime" >= '2017-12-01') AND
("calltime" <= '2017-12-03') AND
(S."id_brand"='6') AND
C.source_id > 50
GROUP BY ST.name
ORDER BY count(*) DESC LIMIT 50
All I did was change it to count(*) and add AND C.source_id > 50 to the Where clause. Let's see if this changes the count.
Also you could just run this:
SELECT
count(*)
FROM "calls" C
INNER JOIN "site" S ON S.id=C.site_id
INNER JOIN "sources" ON sources.id=C.source_id
INNER JOIN "brand" B ON B.id = S.id_brand
INNER JOIN "source_types" ST ON ST.id = "sources".type_id
WHERE
("calltime" >= '2017-12-01') AND
("calltime" <= '2017-12-03') AND
(S."id_brand"='6')
This gives you a total count of all the rows (I removed the GROUP BY). If this number equals the total of your grouped row counts, then they really are the counts. We are looking for 127 which is 49 + 30 + 21 + 13 + 9 + 4 + 1
I hope this helps.

Related

Mysql: how to get Inverse result for given condition?

I wrote a query to get exactly opposite of result, what my query produces.
query 1:
select count(*) from DB.titlecard tt
join _date d on d.td_id = tt.td_id
join sometask s on s.s_id = tt.s_id and d.em_id = s.em_id
where d.`date` > "2019-01-01";
it gives me count of 21354 result.
query 2: (Similar query without sometask join)
select count(*) from DB.titlecard tt
join _date d on d.td_id = tt.td_id
where d.`date` > "2019-01-01";
which produces 28984
i need records which is difference of query 2 - query 1
something like this,
but it gives 1000 000 records.
select count(*) from DB.titlecard tt
join _date d on d.td_id = tt.td_id
join sometask s on s.s_id <> tt.s_id and d.em_id = s.em_id
where d.`date` > "2019-01-01";
i know to get difference by comparing both query.
but i am looking for better way within single query (because i have added only one more table in query 1)
this alone was the difference,
query 1:
join sometask s on s.s_id = tt.s_id
condition i want to apply,
join sometask s on s.s_id <> tt.s_id
If you change your JOIN to a LEFT JOIN and then select only the rows where s.id is NULL you will get the count you want:
select count(*) from DB.titlecard tt
join _date d on d.td_id = tt.td_id
left join sometask s on s.s_id = tt.s_id and d.em_id = s.em_id
where d.`date` > "2019-01-01" and s.s_id IS NULL;
This can be quite complicated -- particularly if there are NULL values or duplicate rows. I am guessing, though, that this does what you want:
select count(*) - count(s.s_id)
from DB.titlecard tt join
d
on d.td_id = tt.td_id left join
sometask s
on s.s_id = tt.s_id and d.em_id = s.em_id
where d.`date` > '2019-01-01';

i want to display all records from 2 or more queries which are not in left queries too

i have queries like this
SET #curr_date = '2017-03-23';
SELECT
curr_week.mid AS MID,
curr_week.EDC AS Merchant_Name ,
COALESCE(curr_week.amount,0) AS Total_Amount_Curr_Week,
COALESCE(curr_week.total_trx,0) AS Total_Trx_Curr_Week,
COALESCE(curr_week.total_user,0) AS Total_User_Curr_Week,
COALESCE(last_week.amount,0) AS Total_Amount_Last_Week,
COALESCE(last_week.total_trx,0) AS Total_Trx_Last_Week,
COALESCE(last_week.total_user,0) AS Total_User_Last_Week
FROM
(
SELECT a.*, b.total_user
FROM
(
SELECT a1.owner_name AS MID, m.name AS EDC,SUM(t1.amount) AS amount, COUNT(t1.id) AS total_trx
FROM members m
JOIN accounts a1 ON a1.member_id = m.id
JOIN transfers t1 ON a1.id = t1.to_account_id
WHERE DATE(t1.DATE) = (#curr_date - INTERVAL 1 DAY)
GROUP BY a1.owner_name
) AS a
JOIN
(-- get total user
SELECT COUNT(r.ecash_no) AS total_user, r.mid, r.merchant_name
FROM
(
SELECT a.`owner_name` AS ecash_no,
a1.owner_name AS MID,
m.name AS merchant_name
FROM accounts a1
JOIN transfers t1 ON a1.id = t1.to_account_id
JOIN members m ON a1.member_id = m.id
JOIN accounts a ON a.id = t1.from_account_id
WHERE DATE(t1.date) = (#curr_date - INTERVAL 1 DAY)
GROUP BY a.owner_name,m.`name`
) AS r
GROUP BY r.mid
) AS b ON a.mid = b.mid
) AS curr_week
JOIN
(
-- last week
SELECT a.*, b.total_user
FROM
(
SELECT a1.owner_name AS MID, m.name AS EDC,SUM(t1.amount) AS amount, COUNT(t1.id) AS total_trx
FROM members m
JOIN accounts a1 ON a1.member_id = m.id
JOIN transfers t1 ON a1.id = t1.to_account_id
WHERE DATE(t1.DATE) = (#curr_date - INTERVAL 1 DAY) - INTERVAL 1 WEEK
GROUP BY a1.owner_name
) AS a
JOIN
(-- get total user
SELECT COUNT(r.ecash_no) AS total_user, r.mid, r.merchant_name
FROM (
SELECT a.`owner_name` AS ecash_no,
a1.owner_name AS MID,
m.name AS merchant_name
FROM accounts a1
JOIN transfers t1 ON a1.id = t1.to_account_id
JOIN members m ON a1.member_id = m.id
JOIN accounts a ON a.id = t1.from_account_id
WHERE DATE(t1.date) = (#curr_date - INTERVAL 1 DAY) - INTERVAL 1 WEEK
GROUP BY a.owner_name,m.`name`
) AS r
GROUP BY r.mid
) AS b ON a.mid = b.mid
) AS last_week ON curr_week.mid = last_week.mid
how can i retrieve all EDC value from joined queries like that.
because if i use join , it displayed only the same values.
and if i use left join, it follows the value from the left query
is there any way to display everything with join?
You can simulate a full outer join of the two tables using the following:
SELECT COALESCE(a.ColA, b.ColA) AS ColA,
COALESCE(a.ColB, b.ColB) AS ColB
FROM tableA a
LEFT JOIN tableB b ON a.ColA = b.ColA
UNION
SELECT COALESCE(a.ColA, b.ColA) AS ColA,
COALESCE(a.ColB, b.ColB) AS ColB
FROM tableA a
RIGHT JOIN tableB b ON a.ColA = b.ColA;
Note: I've assumed that only ColA is the join column. You can add ColB as a join column as well, or use only ColB as a join column. This really depends on the design of your table, but the general approach I gave should still work.
Output:
Demo here:
Rextester

How can I select the second minimal value within a inner join?

I have this query
select c.id, c.name, c.email, c.totalpets, min(p.date_created) as first_order,
min(p.weight) as min_weight_bought,
max(p.weight) as max_weight_bought,
count(p.ordernumber) as total_orders
from orders p
inner join customers c
on p.customer_id = c.id
where p.approved = 1
and c.totalpets >= 1
group by c.id
having total_orders > 1
Note that first_order gives me the first result of the row, right? I am trying to get customer first order and customer second order. How can i do that within this inner join?
Thanks
SELECT c1.id,
c1.name,
c1.email,
c1.totalpets,
p1.date_created
FROM orders p1
INNER JOIN customers c1
ON p1.customer_id = c1.id
WHERE
(
SELECT COUNT(*)
FROM orders p2
INNER JOIN customers c2
ON p2.customer_id = c2.id
WHERE c2.id = c1.id AND p2.date_created <= p1.date_created
) <= 2
ORDER BY c1.id;
Here is a running demo which shows a simplified version of the above query (and simplified data set) in action:
SQLFiddle

SQL: Sum factor*value in a LEFT JOIN

I would like to get some information: I got a table called "invoices" and a table called "invoice_positions".
All personal information about a customer are stored in "invoices". All positions are stored in "invoice_positions".
Well, now I would like to know the total sum of all matching positions:
I got this invoice-entry:
id: 1
customer: 4
I got this invoice-positions-entry:
id: 1
invoiceid: 1
factor: 2
value: 5
id: 2
invoiceid: 1
factor: 1
value: 5
The result should be: 2*5+1*5 = 15
This is my query so far:
SELECT DISTINCT a.*,SUM(ip.factor * ip.value) as totalsum,om.orderid,o.userid as userid,c.lastname as customer_lastname, c.firstname as customer_firstname, c.company as customer_company,uc.name AS editor,created_by.name AS created_by
FROM `o45_hero_invoices` AS a
LEFT JOIN o45_hero_invoices_positions AS ip ON ip.invoiceid=a.id
LEFT JOIN o45_hero_invoices_mapping AS om ON om.invoiceid=a.id
LEFT JOIN o45_hero_orders AS o ON o.id=om.orderid
LEFT JOIN o45_hero_customers AS c ON c.userid=o.userid
LEFT JOIN o45_users AS uc ON uc.id=a.checked_out
LEFT JOIN o45_users AS created_by ON created_by.id = a.created_by
WHERE (a.state IN (0, 1))
ORDER BY a.id asc
But my result is not 15 - it's 30.
you will no longer need the distinct with the group by.
a.* will have to be split into individual columns you want to return in results.
group by has been added below for known columns
.
SELECT a.*,SUM(ip.factor * ip.value) as totalsum,
om.orderid, o.userid as userid, c.lastname as customer_lastname,
c.firstname as customer_firstname, c.company as customer_company,
uc.name AS editor,
created_by.name AS created_by
FROM `o45_hero_invoices` AS a
LEFT JOIN o45_hero_invoices_positions AS ip ON ip.invoiceid=a.id
LEFT JOIN o45_hero_invoices_mapping AS om ON om.invoiceid=a.id
LEFT JOIN o45_hero_orders AS o ON o.id=om.orderid
LEFT JOIN o45_hero_customers AS c ON c.userid=o.userid
LEFT JOIN o45_users AS uc ON uc.id=a.checked_out
LEFT JOIN o45_users AS created_by ON created_by.id = a.created_by
WHERE (a.state IN (0, 1))
GROUP BY a.Field1, a.Field2, A.Field3...,
om.orderid, o.userid, c.lastname, c.firstname,
c.company, uc.name, created_by.name
ORDER BY a.id asc

inner join 4 tables with group, order by, having clause

I have 4 table and i want to extract: id, nume, localitate, masina_id, nr_inmatriculare, an_fabricatie, rafinarie, marca, and sum (quantity+deliver_quantity) as total_quantity group by an_fabricatie , Order by marca, and put some having clouse.
I don’t know how to make this.
My query is as bellow , but I think isn't correct.
select c.id, c.nume,c.localitate,l.masina_id, i.nr_inmatriculare, i.an_fabricatie,
i.rafinarie, m.marca from clienti c inner join livrari l on c.id = l.id inner join incarcari I on l.incarcare_id = l.livrari_id inner join masina m on i.id_marca = m.id, sum(select quantity, deliver_quantity) as total_quantity group by an_fabricatie having quantity >1000 order by marca;
Incarcari table
Id|livrari_id|id_marca|nr_inmatriculare|an_fabricatie|rafinarie|aviz_incarcare|quantity|
Livrari table
Id|masina_id|client_id|incarcare_id|deliver_quantity|aviz_livrare
Masini table
Id|numar_inmatriculare|marca|an_fabricatie|
Clienti table
Id|nume|localitate|date_add|date_upd|
SELECT c.id, c.nume, c.localitate, l.masina_id, i.nr_inmatriculare, i.an_fabricatie, i.rafinarie, m.marca, (SUM(i.quantity) + SUM(l.deliver_quantity)) AS total_quantity
FROM clienti c
INNER JOIN livrari l ON c.id = l.id
INNER JOIN incarcari i ON l.incarcare_id = i.livrari_id
INNER JOIN masini m ON i.id_marca = m.id
GROUP BY i.an_fabricatie, c.id, c.nume,c.localitate,l.masina_id, i.nr_inmatriculare, i.rafinarie, m.marca
HAVING i.quantity > 1000
ORDER BY m.marca DESC;