COUNT and SELECT into the same query in mySQL - mysql

Form my two tables, I want to select SUB_Limit and count the number of rooms (only the active one).
So the query should returns me something like this:
|-----------|------------|-------------|
| SUB_Limit | ROO_Number | ROO_HotelId |
|-----------|------------|-------------|
| 10 | 0 | 1 |
| 15 | 3 | 2 |
| 5 | 2 | 3 |
| 25 | 0 | 4 |
|-----------|------------|-------------|
Why this query do not return me the desired output please ?
SELECT
ROO_HotelId,
SUB_Limit,
COUNT(ROO_Id) AS ROO_Number
FROM ___Rooms
LEFT JOIN ___Subscriptions
ON ___Rooms.ROO_HotelId = ___Subscriptions.SUB_HotelId
WHERE ROO_Status = 'active'
AND SUB_HotelId = 1
AND ROO_HotelId = 1
Actually, it gave me:
|-----------|------------|
| SUB_Limit | ROO_Number |
|-----------|------------|
| 15 | 3 |
| 5 | 2 |
|-----------|------------|
So I haven't the ___Subscriptions with no rooms.
Here the SQL Fiddle for help.
Thanks in advance.

The query below gives you the result you want.
SELECT
SUB_HotelId,
SUB_Limit,
COUNT(ROO_Id) AS ROO_Number
FROM ___Subscriptions
LEFT JOIN ___Rooms ON
___Rooms.ROO_HotelId = ___Subscriptions.SUB_HotelId
WHERE ROO_Status = 'active' or ROO_Status is null
GROUP BY SUB_HotelId
You need to check for ROO_Status = 'active' or NULL because if the subscription is not linked to a room, there will be no value for ROO_Status. Also, you need to group on SUB_HotelId, because ROO_HotelId will also be null if there is no room to join the subscription to.
Link to fiddle: http://sqlfiddle.com/#!9/c6920c/35

Related

Is there a way to select data from one column in SQL table to get table with multiple columns?

So I have two SQL tables: one with id and in the other is meta value and meta_key. I joined them so it looks something like this:
+------+------------+----------+
| id | meta_value | meta_key |
+------+------------+----------+
| 1544 | product1 | 1 |
| 1544 | 2 | 2 |
| 1545 | product2 | 1 |
| 1545 | 5 | 2 |
| 1546 | product3 | 1 |
| 1546 | 10 | 2 |
+------+------------+----------+
And I want to get a query that would show me a table like this:
+------+------------+------------+
| id | meta_value | meta_value |
+------+------------+------------+
| 1544 | product1 | 2 |
| 1545 | product2 | 5 |
| 1546 | product3 | 10 |
+------+------------+------------+
The SQL query for first table looks like this:
SELECT
wprq_gf_entry.id,
wprq_gf_entry_meta.meta_value,
wprq_gf_entry_meta.meta_key
FROM
wprq_gf_entry
INNER JOIN wprq_gf_entry_meta ON wprq_gf_entry.id = wprq_gf_entry_meta.entry_id
WHERE
wprq_gf_entry_meta.form_id = 6
Is there a way to do this? ... Thank you!
You can use JOIN, but you need two of them:
SELECT e.*, m1.meta_value, m2.meta_value
FROM wprq_gf_entry e JOIN
wprq_gf_entry_meta m1
ON e.id = m1.entry_id AND m1.meta_key = 1 JOIN
wprq_gf_entry_meta m2
ON e.id = m2.entry_id AND m2.meta_key = 2;
You can use the table you created, let's call it joined_table.
With joined_table as(
SELECT
wprq_gf_entry.id,
wprq_gf_entry_meta.meta_value,
wprq_gf_entry_meta.meta_key
FROM wprq_gf_entry
INNER JOIN wprq_gf_entry_meta ON wprq_gf_entry.id
= wprq_gf_entry_meta.entry_id
WHERE wprq_gf_entry_meta.form_id = 6
)
Were dividing it into two tables - one with meta-key = 1 and the other with meta-key = 2.
Then, we are joining them
Select jt.id, jt.meta_value as meta_value_1,
jt2.meta_value as meta_value_2
From joined_table jt
Join joined_table jt2
On jt.id = jt2.id
And jt2.meta_key = 2
Where jt.meta_key = 1

Join table in mySQL return me NULL if joined table don't contain row

Here my tables structure:
___Rooms
|--------|-------------|
| ROO_Id | ROO_HotelId |
|--------|-------------|
| 1 | ABC123 |
| 2 | ABC123 |
| 3 | ABC123 |
|--------|-------------|
___Subscriptions
|-------------|-----------|
| SUB_HotelId | SUB_Limit |
|-------------|-----------|
| ABC123 | 19 |
| XYZ987 | 23 |
|-------------|-----------|
This query work when ___Rooms has a rows with desired HotelId.
SELECT
COUNT(ROO_Id) AS SUB_RoomNumber,
SUB_Limit
FROM ___Subscriptions
LEFT JOIN ___Rooms
ON ___Rooms.ROO_HotelId = ___Subscriptions.SUB_HotelId
WHERE SUB_HotelId = 'ABC123'
AND ROO_HotelId = 'ABC123'
|----------------|-----------|
| SUB_RoomNumber | SUB_Limit |
|----------------|-----------|
| 3 | 19 |
|----------------|-----------|
For hotel XYZ987, this hotel do not have actually room in ___Rooms, and the query return me NULL for SUB_Limit :
|----------------|-----------|
| SUB_RoomNumber | SUB_Limit |
|----------------|-----------|
| 0 | NULL |
|----------------|-----------|
Why please ?
Do not check for ROO_HotelId = 'XYZ987', inside the Where condition. If there is no matching ROO_HotelId in the __Rooms table, no data would appear (if using Where).
Basically, once you have done Join between the tables, ON HotelId, you only need to put Where condition for one of the tables. In the case of Inner Join, either of the tables can be used. However, in the case of Left join, you need to use the left table.
Use the following:
SELECT
COUNT(ROO_Id) AS SUB_RoomNumber,
SUB_Limit
FROM ___Subscriptions
LEFT JOIN ___Rooms
ON ___Rooms.ROO_HotelId = ___Subscriptions.SUB_HotelId
WHERE SUB_HotelId = 'XYZ987'

SELECT and COUNT in one query from two tables with mySQL

Here my tables structure:
___Rooms
|--------|-------------|------------|
| ROO_Id | ROO_HotelId | ROO_Status |
|--------|-------------|------------|
| 1 | 1 | active |
| 2 | 1 | active |
| 3 | 1 | inactive |
|--------|-------------|------------|
___Subscriptions
|-------------|-----------|
| SUB_HotelId | SUB_Limit |
|-------------|-----------|
| 1 | 24 |
|-------------|-----------|
I want to select SUB_Limit and count the number of rooms (only the active one).
So the query should returns me something like this:
|-----------|------------|
| SUB_Limit | ROO_Number |
|-----------|------------|
| 24 | 2 |
|-----------|------------|
Why this query do not return me the desired output please ?
SELECT
SUB_Limit,
COUNT(ROO_Id) AS ROO_Number
FROM ___Rooms
LEFT JOIN ___Subscriptions
ON ___Rooms.ROO_HotelId = ___Subscriptions.SUB_HotelId
WHERE ROO_Status = 'active'
AND SUB_HotelId = 1
AND ROO_HotelId = 1
Actually, it gave me:
|-----------|------------|
| SUB_Limit | ROO_Number |
|-----------|------------|
| NULL | 0 |
|-----------|------------|
Try this below query once
SELECT
SUB_Limit, COUNT(ROO_Id) AS ROO_Number FROM
___rooms r,___subscriptions s
WHERE r.ROO_HotelId=s.SUB_HotelId AND ROO_Status='active'
Try below query:
SELECT s.sub_limit, count(ROO_Id)
FROM ___Rooms r
INNER JOIN ___Subscription s ON (s.SUB_HotelId = r.ROO_HotelId)
WHERE s.SUB_HotelId = 1
and r.ROO_STATUS = 'active'
You forgot GROUP BY
SELECT
S.SUB_Limit,
COUNT(*) AS ROO_Number
FROM ___Rooms AS R
RIGHT JOIN ___Subscriptions AS S
ON R.ROO_HotelId = S.SUB_HotelId
WHERE R.ROO_Status = 'active'
AND S.SUB_HotelId = 1
GROUP BY ROO_HotelId
UPD: group by is not necessary as we need only the number of all lines. Also RIGHT JOIN could not be available for your particular MySQL engine (unlike LEFT JOIN or INNER JOIN), so you would better use UNION constructions, to catch zero intersections with main table if I'm not mistaken.

Using left join with min

I am trying to connect two tables with left join and a date.
My SQL Query
SELECT
ord.`ordernumber` bestellnummer,
his.`change_date` zahldatum
FROM
`s_order` ord
LEFT JOIN
`s_order_history` his ON ((ord.`id`=his.`orderID`) AND (ord.`cleared`=his.`payment_status_id`)) #AND MIN(his.`change_date`)
WHERE
ord.`ordertime` >= \''.$dateSTART.'\' AND ord.`ordertime` <= \''.$dateSTOP.'\'' ;
s_order
+----+---------------------+---------+-------------+
| id | ordertime | cleared | ordernumber |
+----+---------------------+---------+-------------+
| 1 | 2014-08-11 19:53:43 | 2 | 123 |
| 2 | 2014-08-15 18:33:34 | 2 | 125 |
+----+---------------------+---------+-------------+
s_order_history
+----+-------------------+-----------------+---------+---------------------+
| id | payment_status_id | order_status_id | orderID | orderID change_date |
+----+-------------------+-----------------+---------+---------------------+
| 1 | 1 | 5 | 1 | 2014-08-11 20:53:43 |
| 2 | 2 | 5 | 1 | 2014-08-11 22:53:43 |
| 3 | 2 | 7 | 1 | 2014-08-12 19:53:43 |
| 4 | 1 | 5 | 2 | 2014-08-15 18:33:34 |
| 5 | 1 | 6 | 2 | 2014-08-16 18:33:34 |
| 6 | 2 | 6 | 2 | 2014-08-17 18:33:34 |
+----+-------------------+-----------------+---------+---------------------+
Wanted result:
+-------------+---------------------+
| ordernumber | change_date |
+-------------+---------------------+
| 123 | 2014-08-11 22:53:43 |
| 125 | 2014-08-17 18:33:34 |
+-------------+---------------------+
The problem I have is getting only the date, where the cleared/payment_status_id value has been changed in s_order. I currently get all dates where the payment_status_id matches the current cleared value, but I only need the one, where it happend first.
This is only an excerpt of the actually query, since the original is a lot longer (mostly more left joins and a lot more tables).
You can group data by ordernumber
SELECT
ord.`ordernumber` bestellnummer,
MIN(his.`min_change_date`) as zahldatum
FROM
`s_order` ord
LEFT JOIN
`s_order_history` his ON ((ord.`id`=his.`orderID`) AND (ord.`cleared`=his.`payment_status_id`)) #AND MIN(his.`change_date`)
WHERE
ord.`ordertime` >= \''.$dateSTART.'\' AND ord.`ordertime` <= \''.$dateSTOP.'\''
GROUP BY
ord.`ordernumber`;
or you can group data in a subquery:
SELECT
ord.`ordernumber` bestellnummer,
his.`min_change_date` zahldatum
FROM
`s_order` ord
LEFT JOIN (
SELECT
orderID, payment_status_id, MIN(change_date) as min_change_date
FROM
s_order_history
GROUP BY
orderID, payment_status_id
) his ON (ord.`id` = his.`orderID` AND ord.`cleared` = his.`payment_status_id`)
WHERE
ord.`ordertime` >= \''.$dateSTART.'\' AND ord.`ordertime` <= \''.$dateSTOP.'\'';
Try this:
select s_order.ordernumber, min(s_order_history.change_date)
from s_order left join s_order_history
on s_order.id = s_order_history.orderID
and s_order.cleared = s_order_history.payment_status_id
group by s_order.order_id
SELECT ord.`ordernumber` bestellnummer,
MIN( his.`change_date` ) zahldatum
...
GROUP BY ord.`ordernumber`
MIN is an aggregate function so you can't use it in a JOIN straight up like you've tried above. You also are not comparing it to a value in your JOIN.
You'll want to do something like:
his.`change_date` = (SELECT MIN(his.`change_date`) FROM s_order_history where ord.`id` = his.`orderID`)
in your JOIN.

MySQL: joining tables with multi results rows to one row

I have 4 tables:
secu_content
| id | created | modified |
| 910 | 26/12/1982 | 28/12/1984 |
| 911 | 24/12/1982 | 25/12/1984 |
secu_data
| element_id | field_id | data |
| 1 | 1 | 25/12/1984 |
| 2 | 1 | 26/12/1984 |
| 3 | 1 | 27/12/1984 |
| 4 | 1 | 25/12/1984 |
| 4 | 2 | google.com |
secu_elements
| id | item_id |
| 1 | 891 |
| 2 | 711 |
| 3 | 204 |
| 4 | 911 |
secu_fields
| id | type |
| 1 | date |
| 2 | input |
Table secu_content, contains many articles, where the id is the article id.
The other 3 tables gives additional information and I want to join them.
I want to get results that includes all secu_content rows and all the columns + calc_date + calc_link
calc_date <- the data column from secu_data where field_id=1 (see secu_fields)
calc_link <- the data column from secu_data where field_id=2 (see secu_fields)
The problem is that I get 2 rows where secu_content id=911 (one row with the correct calc_date and second row with the correct calc_link), and I need one row with both.
This is my SQL:
SELECT a.id
, a.created
, a.modified
, fe.item_id AS calc_date_item_id
, fd.data AS calc_date
, CASE WHEN fd.data IS NOT NULL AND ff.type = "date" THEN fd.data
WHEN a.modified = '0000-00-00 00:00:00' THEN a.created ELSE a.modified
END as calc_date
, CASE WHEN fd.data IS NOT NULL AND ff.type = "input" THEN fd.data
END as calc_link
FROM secu_content AS a
LEFT
JOIN secu_fieldsandfilters_elements AS fe
ON fe.item_id = a.id
AND fe.content_type_id=1
LEFT
JOIN secu_fieldsandfilters_data AS fd
ON fd.element_id = fe.id
LEFT
JOIN secu_fieldsandfilters_fields as ff
ON ff.id = fd.field_id
ORDER BY a.id DESC;
Thanks in advance
Israel
Fast and dirty solution is to use second join to secu_data like that (simplified, add logic you need)
SELECT id, d1.data as `calc_date`, d2.data as `calc_link`
FROM secu_content
LEFT JOIN secu_data d1 ON secu_content.id = d1.element_id AND field_id = 1
LEFT JOIN secu_data d2 ON secu_content.id = d2.element_id AND field_id = 2