HAVING row exist - mysql

Following database sample
id | date | customer | ...
-----------------------------------------
1 2016-07-05 1
2 2016-07-05 2
3 2016-07-06 1
4 2016-07-07 1
5 2016-07-07 2
I want to select all customers which have an entry at 2016-07-07, but not at 2016-07-06.
At first, I thought I'd do this using WHERE:
SELECT * FROM table
WHERE EXISTS ( SELECT * FROM table WHERE date = '2016-07-07' )
AND NOT EXISTS ( SELECT * FROM table WHERE date = '2016-07-06' )
GROUP BY customer
but since WHERE is executed before GROUP BY, the result can only by empty - there IS a record in table at 2016-07-06.
So, using HAVING, how would I do this? I am having difficulties checking for row existance in a HAVING clause. Something like:
SELECT * FROM table
GROUP BY customer
HAVING exists date '2016-07-07'
AND not exists date '2016-07-06'

Group by the customer and take only those groups having at least one date entry for 2016-07-07 and none for 2016-07-06
SELECT customer
FROM your_table
GROUP BY customer
HAVING sum(date = '2016-07-07') > 0
AND sum(date = '2016-07-06') = 0

SELECT customer FROM table t
WHERE EXISTS ( SELECT * FROM table t1
WHERE date = '2016-07-07' AND t.customer = t1.customer)
AND NOT EXISTS ( SELECT * FROM table t2
WHERE date = '2016-07-06' AND t.customer = t2.customer)
GROUP BY customer

Related

get the total count but exclude certain condition

Hello I had this table:
id | user_id | status
1 | 34 | x
2 | 35 | x
3 | 42 | x
4 | 42 | y
My goal is to count the data with X status except if the user has a another data with Y status, it will exclude in the count. So instead of 3, it will only count 2 since the 3rd row has another data which is the 4th row with y status.
SELECT * FROM logs
AND user_id NOT IN (SELECT user_id FROM logs WHERE status = 'y')
GROUP BY user_id;
We can try the following aggregation approach:
SELECT COUNT(*) AS cnt
FROM
(
SELECT user_id
FROM logs
GROUP BY user_id
HAVING MIN(status) = MAX(status) AND
MIN(status) = 'x'
) t;
The above logic only counts a user having one or more records only having x status.
You can do it this way, I only modify a bit on your sql
SELECT COUNT(*) FROM (
SELECT u_id FROM tbl WHERE u_id NOT IN
(SELECT u_id FROM tbl WHERE status = 'y')
GROUP BY u_id
) as t
You can use inner join:
SELECT
count(t1.id) AS `cnt`
FROM
`test` AS t1,
`test` AS t2
WHERE
t2.`status`='y'
&& t1.`user_id` != t2.`user_id`;

How to get number of same id's where the item was found in mysql?

Let's say I have table like this:
some_id
date
1
2022-02-01
2
2022-02-02
3
2022-02-03
3
2022-02-04
3
2022-02-05
3
2022-02-06
I want to get the number of rows based on the id where the date was found?
I tried this but it's not working:
SELECT COUNT(id) FROM dates WHERE date = '2022-02-04'
Expected output should be 4 rows since there are 4 same id's where the 2022-02-04 was found.
This should do the job:
SELECT COUNT(*) FROM tbl
WHERE id IN (
SELECT id FROM tbl WHERE `date`='2022-02-04'
)
An exists query should do it:
SELECT id, COUNT(*)
FROM t
WHERE EXISTS (
SELECT 1
FROM t AS x
WHERE x.id = t.id
AND x.date = '2022-02-04'
)
GROUP BY id
Using exists logic we can try:
SELECT COUNT(*)
FROM dates d1
WHERE EXISTS (SELECT 1 FROM dates d2
WHERE d2.some_id = d1.some_id AND
d2.date = '2022-02-04');

comparing in the same table based on latest creation date

id|code|transaction_date |amount|status|record_status|creation_date
1 |0001|2021-12-10 00:00:00| 10.00|Succ |D |2021-12-10 00:00:00
2 |0001|2021-12-10 00:00:00| 10.00|Fail |D |2021-12-11 00:00:00
3 |0001|2021-12-10 00:00:00| 10.00| |A |2021-12-12 00:00:00
I want to select recod_status = A, code = 001 and transaction date is 2021-12-10'
SELECT * FROM TestTable
WHERE DATE(alloc.trans_date) IN ('2021-12-10') // Need filter by few dates
AND record_status = 'A'
AND code = '001';
but I only want the record to return if the same code = 001 and transaction date is 2021-12-10' but record_status = 'D', status = 'Fail' and the creation_date is latest.
Example above will return 3rd record because 2nd record which creation_date is the latest and status = 'Fail' and record_status = 'D'.
I just want to compare the latest creation_date.'
I can select the latest transaction where the record_status = 'D'
SELECT * FROM TestTable
WHERE creation_date = (
SELECT MAX(creation_date)
FROM TestTable
WHERE DATE(trans_date) IN ('2021-12-10')
AND record_status = 'D'
)
AND record_status = 'D'
AND code = '001';
Looks like:
SELECT t1.*
-- or SELECT t2.* - depends on the task which is unclear for me yet
FROM ( SELECT *
FROM table
WHERE DATE(trans_date) = '2021-12-10'
ORDER BY creation_date DESC LIMIT 1 ) t1
JOIN table t2 ON DATE(t1.trans_date) = DATE(t2.trans_date)
AND t1.creation_date > t2.creation_date
WHERE t1.record_status = 'A'
AND t2.record_status = 'D'
AND NOT EXISTS ( SELECT NULL
FROM table t3
WHERE DATE(t1.trans_date) = DATE(t3.trans_date)
AND t1.creation_date > t3.creation_date
AND t3.creation_date > t2.creation_date )
Subquery t1 selects the most last row, and further it is checked for status A.
Table copy t2 selects the row which is adjacent to the row selected in subquery (NOT EXISTS checks that there is no any row between), and further it is checked for status D.

Mysql - Update only 1 row from same records

I need to update row which having same value in debit column & only row which having create_date ASC basically 2019-11-15
I am having transaction table with following data
table name - tbl_transactions
id client_id user_id debit add_date
1 9991101 1 7.69 2019-11-15
2 9991101 1 7.69 2019-11-30
3 9991101 2 28.9 2019-11-15
4 9991101 2 11.49 2019-11-30
Now i just want to UPDATE record which have same value in column "debit" & date "2019-11-15"
which means only id-1 will be get updated.
id client_id user_id debit add_date
1 999110100 1 7.69 2019-11-15
We can add additional 00 to client_id field, i have tried with below sql but seems its not working
UPDATE tbl_transactions
SET client_id=999110100
WHERE id IN (
SELECT *
FROM tbl_transactions
WHERE client_id=9991101
AND DATE(create_date)='2019-11-15'
GROUP BY user_id, debit HAVING COUNT(*) = 2 )
Thanks in advance.
From what I understood from your question, you can try a query like
UPDATE
`tbl_transactions`
SET
`COLUMN_NAME` = DESIRED_VALUE
WHERE
`debit` = 7.69
AND
`add_date` = '2019-11-15'
You just need to replace COLUMN_NAME in the above query with your desired column name and it's respective value ahead of it. Do let me know if that's what you're trying to achieve or something else.
Mysql cannot specify target table for update in FROM clause.
You need to use subquery select them in a temporary table and update it,
And you can use CONCAT to concat your client_id with 00,
According to your post, you need the same debit and order by created_date ASC,
however, mysql cannot just order a field in group, so you can do it like this:
UPDATE
`tbl_transactions`
SET
`client_id` = CONCAT(client_id, '00')
WHERE id IN (
SELECT id FROM (
SELECT t2.id, t2.user_id t2.created_date FROM
(
SELECT id, user_id, MIN(created_date) AS created_date
FROM tbl_transactions
WHERE client_id=9991101
GROUP BY user_id, debit
HAVING COUNT(*) >= 2
) AS t1
INNER JOIN tbl_transactions AS t2
ON t1.user_id = t2.user_id AND t1.debit = t2.debit AND t2.client_id = 9991101 AND t1.created_date = t2.created_date
GROUP BY t2.user_id
) AS temp_table
)

Run SQL statement based on sql count

I want to run one SQL query based on first COUNT sql query:
SET #result = "SELECT count(*) FROM ip_addresses WHERE id > (SELECT id FROM ip_addresses WHERE in_use=1) ORDER BY id LIMIT 1"
CASE WHEN (#result > 0)
THEN SELECT * FROM ip_addresses WHERE id > (SELECT id FROM ip_addresses WHERE in_use=1) ORDER BY id LIMIT 1
ELSE SELECT * FROM ip_addresses WHERE in_use!=1 ORDER BY id LIMIT 1
END
Basically what I'm trying to do is, I want to get the next record in_use=0 of WHERE in_use=1. And if the in_use=1 record is last record of the table it should get the first record of table with in_use=0.
More explaination:
if ip_addresses table have following data
id| ip |in_use
1 | 192.168.1.5|1
2 | 89.58.1.2 |0
3 | 58.98.58.6 |0
Now it should return second record.
And if ip_addresses table have following data
id| ip |in_use
1 | 192.168.1.5|0
2 | 89.58.1.2 |0
3 | 58.98.58.6 |1
Now it should return first record.
You have several issues. The most important is that control flow logic is only allowed in programming blocks.
However, you can accomplish what you want with a single query. For instance:
(SELECT ia.*, 1 as priority
FROM ip_addresses ia
WHERE id > (SELECT id FROM ip_addresses WHERE in_use = 1)
ORDER BY id
LIMIT 1
)
UNION ALL
(SELECT ia.*, 2 as priority
FROM ip_addresses ia
WHERE in_use <> 1
ORDER BY id
LIMIT 1
)
ORDER BY priority
LIMIT 1
Building on xQbert's answer:
select IP
from ( select case when id >
( select min( ID )
from IP_ADDRESES
where in_use = 1 )
then ID - ( select max( ID ) from IP_ADDRESES )
else id
end case
from IP_ADDRESES as deflated_id,
ip )
order by deflated_id asc
top 1
SELECT A.IP
FROM IP_Addresses A,
( SELECT min(ID) mid
FROM IP_ADDRESES
WHERE in_use= 0
) B
WHERE A.id = B.mid;