Using IF in MySQL's SELECT subquery - mysql

I have the following query:
SELECT `users`.`id`, `login`, `fullname`, `active`, `sex`, `height`,
`special-title`, `language`, `body-fat`,
`main-photo-id`, `main-photo-offset`, `weight`,
`objective`, `level`, `config-comments-type`,
(
SELECT `type`
FROM `users-pro`
WHERE
(`user` = `users`.`id`)
AND
(`starts` <= $time)
AND(
(`ends` > $time)
OR
(`ends` IS NULL)
)
LIMIT 1
) as `account_type`
FROM `users`
I'm wondering how/where do I add an IF statement, so that if the inner SELECT returns NULL (no entries for the user in users-pro, a value 1 would be returned.
This is what I usually do if there is no subquery:
SELECT IF(`rank` = 1, `rank`, 0) as `rank`
However, I don't know how to do this with a subquery.

You can use the ANSI standard coalesce() function for this, by wrapping the subquery in it:
SELECT `users`.`id`, `login`, `fullname`, `active`, `sex`, `height`,
`special-title`, `language`, `body-fat`,
`main-photo-id`, `main-photo-offset`, `weight`,
`objective`, `level`, `config-comments-type`,
coalesce((
SELECT `type`
FROM `users-pro`
WHERE
(`user` = `users`.`id`)
AND
(`starts` <= $time)
AND(
(`ends` > $time)
OR
(`ends` IS NULL)
)
LIMIT 1
), 1) as `account_type`
FROM `users`

Related

Mysql query to get created and resolved defect group by month

The table I am using is like bellow:
CREATE TABLE IF NOT EXISTS `tickets` (
`id` int(6) unsigned NOT NULL,
`created` timestamp ,
`resolved` timestamp ,
PRIMARY KEY (`id`)
) DEFAULT CHARSET=utf8;
INSERT INTO `tickets` (`id`, `created`, `resolved`) VALUES
('1', '2021-01-01', '2021-01-12'),
('2', '2021-02-25', '2021-01-15'),
('3', '2021-03-10', '2021-03-22'),
('4', '2021-03-10', '2021-03-22'),
('5', '2021-03-10', '2021-03-22'),
('6', '2021-03-11', '2021-03-22'),
('7', '2021-03-13', '2021-03-22'),
('8', '2021-03-13', '2021-03-22'),
('9', '2021-04-01', '2021-03-12');
Now I want a query to show me the table with columns like
Month, NumberOfticketsCreated, NumberOfTicketsResolved.
Here is what I tried so far but it does not return what I expect:
SELECT
YEAR(`created`) AS y
, MONTH(`created`) AS m
, COUNT(`created`) as NumberOfticketsCreated
, count(`resolved`) as NumberOfTicketsResolved
FROM tickets
GROUP BY y, m;
Create table t1 with group by 'created'
Create table t2 with group by 'resolved'
then left join above two tables.
select t1.y, t1.m, t1.NumberOfticketsCreated, t2.NumberOfTicketsResolved
from
(SELECT
YEAR(`created`) AS y
, MONTH(`created`) AS m
, MONTH(`resolved`) AS n
, COUNT(`created`) as NumberOfticketsCreated
, count(`resolved`) as NumberOfTicketsResolved
FROM tickets
GROUP BY m) as t1
left join
(SELECT
YEAR(`created`) AS y
, MONTH(`created`) AS m
, MONTH(`resolved`) AS n
, COUNT(`created`) as NumberOdticketsCreated
, count(`resolved`) as NumberOfTicketsResolved
FROM tickets
GROUP BY n) as t2
on t1.m = t2.m

How to get difference or delta of counts entries of each days with window functions?

I have a table with few fields like id, country, ip, created_at. Then I am trying to get the deltas between total entry of one day and total entry of the next day.
CREATE TABLE session (
id int NOT NULL AUTO_INCREMENT,
country varchar(50) NOT NULL,
ip varchar(255),
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id)
);
INSERT INTO `session` (`id`, `country`, `ip`, `created_at`) VALUES
('1', 'IN', '10.100.102.11', '2021-04-05 20:26:02'),
('2', 'IN', '10.100.102.11', '2021-04-05 19:26:02'),
('3', 'US', '10.120.102.11', '2021-04-17 10:26:02'),
('4', 'US', '10.100.112.11', '2021-04-16 12:26:02'),
('5', 'AU', '10.100.102.122', '2021-04-12 19:36:02'),
('6', 'AU', '10.100.102.122', '2021-04-12 18:20:02'),
('7', 'AU', '10.100.102.122', '2021-04-12 23:26:02'),
('8', 'US', '10.100.102.2', '2021-04-16 21:33:01'),
('9', 'AU', '10.100.102.122', '2021-04-18 20:46:02'),
('10', 'AU', '10.100.102.111', '2021-04-04 13:19:12'),
('11', 'US', '10.100.112.11', '2021-04-16 12:26:02'),
('12', 'IN', '10.100.102.11', '2021-04-05 15:26:02'),
('13', 'IN', '10.100.102.11', '2021-04-05 19:26:02');
Now I have written this query to get the delta
SELECT T1.date1 as date, IFNULL(T1.cnt1-T2.cnt2, T1.cnt1) as delta from (
select TA.dateA as date1, MAX(TA.countA) as cnt1 from (
select DATE(created_at) AS dateA, COUNT(*) AS countA
FROM session
GROUP BY DATE(created_at)
UNION
select DISTINCT DATE(DATE(created_at)+1) AS dateA, 0 AS countA
FROM session
) as TA
group by TA.dateA
) as T1
LEFT OUTER JOIN (
select DATE(DATE(created_at)+1) AS date2,
COUNT(*) AS cnt2
FROM session
GROUP BY DATE(created_at)
) as T2
ON T1.date1=T2.date2
ORDER BY date;
http://sqlfiddle.com/#!9/4f5fd26/60
Then I am getting the results as
date delta
2021-04-04 1
2021-04-05 3
2021-04-06 -4
2021-04-12 3
2021-04-13 -3
2021-04-16 3
2021-04-17 -2
2021-04-18 0
2021-04-19 -1
Now, is there any place of improvements/optimizes on it with/or window functions? (I am zero with SQL, still playing around).
Try a shorter version
with grp as (
SELECT t.dateA, SUM(t.cnt) AS countA
FROM session,
LATERAL (
select DATE(created_at) AS dateA, 1 as cnt
union all
select DATE(DATE(created_at)+1), 0 as cnt
) t
GROUP BY dateA
)
select t1.dateA as date, IFNULL(t1.countA-t2.countA, t1.countA) as delta
from grp t1
left join grp t2 on DATE(t2.dateA + 1) = t1.dateA
order by t1.dateA
db<>fiddle

Maria DB - update row with value of previous row + constant

I have table called dobridol with several column.
CREATE TABLE IF NOT EXISTS `dobridol` (
`id` int(6) unsigned NOT NULL,
`dt` varchar(200) NOT NULL,
`p2` int(6) NOT NULL,
`p6` int(6) NOT NULL,
PRIMARY KEY (`id`)
) DEFAULT CHARSET=utf8;
INSERT INTO `dobridol` (`id`, `dt`, `p2`,`p6`) VALUES
('1', '2021-02-28 23:50:00', '100', '600'),
('2', '2021-02-28 23:55:00', '200', '700'),
('3', '2021-03-01 00:00:00', '300', '800'),
('4', '2021-03-01 00:05:00', '400', '900'),
('5', '2021-03-01 00:10:00', '400', '900'),
('6', '2021-03-01 00:15:00', '400', '900'),
('7', '2021-03-01 00:20:00', '500', '1000'),
('8', '2021-03-01 00:25:00', '600', '1100');
The table has values for January and March also.
I want to be able to UPDATE table like that:
I select period as month, then I add constant value (in this case I added 39) to p6 ONLY WHEN p2 value is different than previous row p2.
If this is the case I have to add 39 to PREVIOUS row p6 value.
update dobridol join
(select tt.*,
sum(case when p2 <> prev_p2 then 1 else 0 end) over (order by dt) as cnt
from (select tt.*,
lag(p2) over (order by dt) as prev_p2
from dobridol tt
) tt
) tt
on tt.id = dobridol.id
set dobridol.p6 = cnt * 39 + <PREVIOUS_ROW_p6_VALUE_HAS_TO_BE_HERE>
where cnt > 0
The query should look-like this but I have to replace this <PREVIOUS_ROW_VALUE_HAS_TO_BE_HERE> with the right syntax of picking last row p6. How can I pick it?
Also where to add clause
dobridol.dt BETWEEN '2021-03-01' AND '2021-03-30'
in the SQL query?
If I understand correctly, you can use lag():
update dobridol join
(select tt.*,
lag(p6) over (order by dt) as prev_p6,
sum(case when p2 <> prev_p2 then 1 else 0 end) over (order by dt) as cnt
from (select tt.*,
lag(p2) over (order by dt) as prev_p2
from dobridol tt
) tt
) tt
on tt.id = dobridol.id
set dobridol.p6 = tt.cnt * 39 + tt.prev_p6
where cnt > 0 ;
Here is a db<>fiddle.

Complex insert query with insert into and where subquery in Laravel

I am trying to figure out the best way to code this using Query Builder or Eloquent.
In it's simplest form it should prevent insert of a new buy request if an item already in transactions table. I haven't found any useful reference other than running a complete raw query.
INSERT INTO `transactions`
(`user_id`, `item_id`, `type`, `created_at`, `updated_at`)
SELECT
1, 186808, 'bought', NOW(), NOW()
WHERE
(
SELECT
SUM(
CASE
WHEN `type` = 'bought' THEN 1
WHEN `type` = 'sold' THEN -1
END
)
FROM `transactions`
WHERE
(`item_id`, `user_id`) = (186808, 1)
GROUP BY `item_id`
) = 0
In Laravel, you can use DB::raw(<your_complex_query_here>) to achieve this.
DB::raw("INSERT INTO `transactions`
(`user_id`, `item_id`, `type`, `created_at`, `updated_at`)
SELECT
1, 186808, 'bought', NOW(), NOW()
WHERE
(
SELECT
SUM(
CASE
WHEN `type` = 'bought' THEN 1
WHEN `type` = 'sold' THEN -1
END
)
FROM `transactions`
WHERE
(`item_id`, `user_id`) = (186808, 1)
GROUP BY `item_id`
) = 0");
For more, refer to Laravel docs here https://laravel.com/docs/5.7/queries#raw-expressions

Cannot get 180 day sql date to work

SELECT CTT.BAN, `Company`, `CID`, `FName`, `MInit`,
`LName`, `OName`, `Address`, `City`, `State`,
`PostalCode`, `ActiveDate`, `ClosedDate`, `Draft`,
`Credit`, `BillingCycle`, `BillingFreq`, `Suspended`,
`Paperless` , BTT.Bal
FROM CustomerT CTT
JOIN BalanceT BTT
ON (CTT.BAN = BTT.BAN)
WHERE `Paperless` != '1'
AND `BankDraft` != -1
AND `CreditCard` != -1
AND (`BillingCycle` = '1' OR `BillingCycle` = '0')
AND `Bal` > 2
AND (`AccountClosedDate` IS NULL OR
DATE(`AccountClosedDate`) >= (NOW() - INTERVAL 180 DAY) )
Everything works with this query but the 180 date peice i have tried several things from this site, with no luck. I need to include into the table only the last 6 months closed acount.
try this with DATE_ADD
SELECT CTT.BAN, `Company`, `CID`, `FName`, `MInit`, `LName`, `OName`, `Address`, `City`, `State`, `PostalCode`, `ActiveDate`, `ClosedDate`, `Draft`, `Credit`, `BillingCycle`, `BillingFreq`, `Suspended`, `Paperless` , BTT.Bal
FROM CustomerT CTT
JOIN BalanceT BTT ON
(CTT.BAN = BTT.BAN)
WHERE `Paperless` != '1'
AND `BankDraft` != -1
AND `CreditCard` != -1
AND (`BillingCycle` = '1' OR `BillingCycle` = '0')
AND `Bal` > 2
AND (`AccountClosedDate` IS NULL OR DATE(`AccountClosedDate`) >=DATE_ADD(CURDATE(), INTERVAL -180 DAY))
or use ( CURDATE() - INTERVAL 180 DAY )
SELECT CTT.BAN, `Company`, `CID`, `FName`, `MInit`, `LName`, `OName`, `Address`, `City`, `State`, `PostalCode`, `ActiveDate`, `ClosedDate`, `Draft`, `Credit`, `BillingCycle`, `BillingFreq`, `Suspended`, `Paperless` , BTT.Bal
FROM CustomerT CTT
JOIN BalanceT BTT ON
(CTT.BAN = BTT.BAN)
WHERE `Paperless` != '1'
AND `BankDraft` != -1
AND `CreditCard` != -1
AND (`BillingCycle` = '1' OR `BillingCycle` = '0')
AND `Bal` > 2
AND (`AccountClosedDate` IS NULL OR DATE(`AccountClosedDate`) >=( CURDATE() - INTERVAL 180 DAY ))