MySQL Need advice on Query - mysql

I want to fetch latest 3 news from each news type.
CREATE TABLE IF NOT EXISTS `news` (
`news_id` int(8) NOT NULL AUTO_INCREMENT,
`news_heading` tinytext NOT NULL,
`news_description` text NOT NULL,
`news_date` date DEFAULT NOT NULL,
`news_type` tinyint(1) NOT NULL COMMENT '0- PEP|1 - MEDIA|2 - CONSULTING',
`created_date` datetime NOT NULL,
`modified_date` datetime NULL,
`display` tinyint(1) NOT NULL COMMENT '0- ON | 1 -OFF',
PRIMARY KEY (`news_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=2 ;
Below Query will give me only 1 latest news from all type. Suggest me how we can achieve for top 3 from each type
SELECT * FROM (
SELECT * FROM `news`
ORDER BY `created_date` DESC
) AS TBL
GROUP BY `news_type`

Try this:
SELECT news_id, news_heading, news_description, news_date,
news_type, created_date, modified_date, display
FROM (SELECT news_id, news_heading, news_description, news_date,
news_type, created_date, modified_date, display,
IF(#news_type = #news_type:=news_type, #id:=#id+1, #id:=1) AS id
FROM news, (SELECT #id:=1, #news_type:=0) A
ORDER BY news_type, created_date DESC
) AS A
WHERE id <= 3;

Related

Aggregating existing query to work for multiple rows

I have a ledger table, and right now I have the ability to find the date or NULL if someone is delinquent based on their payment history. I need a query that allows me to find all delinquent members instead of just a specific one.
I need the ability to run a query that gets any member that is delinquent and return to me the member_id and the date of delinquency.
Basically what the original query to find delinquency for a specific member does, just doing every member instead of a specific one.
I have tried:
SELECT DISTINCT member_id, created_at FROM member_ledger_items WHERE
balance > 0 and id > (
IFNULL(
(SELECT id from member_ledger_items WHERE balance <= 0 and member_ledger_items.deleted_at is NULL GROUP BY member_id ORDER BY created_at, id desc LIMIT 1),
0
)
) and `member_ledger_items`.`deleted_at` is null GROUP BY member_id order by created_at asc, id asc;
This is the query to find if a specific member is delinquent:
select `created_at` from `member_ledger_items` where `member_id` = ? and `balance` > 0 and `id` >
(
IFNULL(
(select `id` from `member_ledger_items` where `member_id` = ? and `balance` <= 0 and `member_ledger_items`.`deleted_at` is null order by `created_at` desc, `id` desc limit 1)
, 0)
)
and `member_ledger_items`.`deleted_at` is null order by `created_at` asc, `id` asc limit 1;
Here is the create syntax of the member_ledger_items table:
CREATE TABLE `member_ledger_items` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`member_id` int(10) unsigned NOT NULL,
`status` varchar(20) COLLATE utf8_unicode_ci NOT NULL,
`type` enum('credit','debit') COLLATE utf8_unicode_ci NOT NULL,
`category` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`memo` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`amount` decimal(13,3) DEFAULT NULL,
`autopay` tinyint(1) DEFAULT NULL,
`late` tinyint(1) DEFAULT NULL,
`date` date NOT NULL,
`created_at` timestamp NULL DEFAULT NULL,
`updated_at` timestamp NULL DEFAULT NULL,
`deleted_at` timestamp NULL DEFAULT NULL,
`balance` decimal(13,3) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=53596 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
I need rows with member_id and date of starting delinquency.
Is this possible?
Any help would be appreciated!
SELECT `member_id`,
(SELECT `created_at`
FROM `member_ledger_items` AS MLI2
WHERE `balance` > 0
AND MLI2.`member_id` = MLI.`member_id`
AND `id` > ( Ifnull((SELECT `id`
FROM `member_ledger_items` AS MLI3
WHERE `balance` <= 0
AND MLI3.`member_id` =
MLI2.`member_id`
AND MLI3.`deleted_at` IS NULL
ORDER BY `created_at` DESC,
`id` DESC
LIMIT 1), 0) )
AND MLI2.`deleted_at` IS NULL
ORDER BY `created_at` ASC,
`id` ASC
LIMIT 1) AS created_date
FROM `member_ledger_items` AS MLI
GROUP BY `member_id`;
Ended up being the solution

Mysql : select aggregated values in between dates

I've got mysql query (generated by zf2), it looks like
SELECT `subt`.`from` AS `from`, SUM(ordered) AS `sum_ordered`,
SUM(income) AS `sum_income`, SUM(sales_by_payment) AS
`sum_sales_by_payment`
FROM (
SELECT `w`.`brand` AS `brand`, `w`.`article` AS `article`,
`w`.`subject` AS `subject`, `w`.`size` AS `size`, `w`.`from` AS
`from`, (
SELECT SUM(IFNULL(income,0)) AS `income`) AS `income`, (
SELECT SUM(IFNULL(income_sum_price,0)) AS `income_sum_price`) AS
`income_sum_price`, (
SELECT SUM(IFNULL(ordered,0)) AS `ordered`) AS `ordered`, (
SELECT SUM(IFNULL(ordered_sum_price,0)) AS `ordered_sum_price`) AS
`ordered_sum_price`, (
SELECT SUM(IFNULL(ordered_max_by_day,0)) AS `ordered_max_by_day`) AS
`ordered_max_by_day`, (
SELECT SUM(IFNULL(return_before_payment,0)) AS
`return_before_payment`) AS `return_before_payment`, (
SELECT SUM(IFNULL(return_before_payment_sum_price,0)) AS
`return_before_payment_sum_price`) AS
`return_before_payment_sum_price`, (
SELECT SUM(IFNULL(sales_by_payment,0)) AS `sales_by_payment`) AS
`sales_by_payment`, (
SELECT SUM(IFNULL(sales_by_payment_sum_price,0)) AS
`sales_by_payment_sum_price`) AS `sales_by_payment_sum_price`, (
SELECT SUM(IFNULL(`return`,0)) AS ```return```) AS `return`, (
SELECT SUM(IFNULL(`return_sum_price`,0)) AS ```return_sum_price```)
AS `return_sum_price`, (
SELECT SUM(IFNULL(`stock`,0)) AS ```stock```) AS `stock`, (
SELECT SUM(IF (sales_by_payment IS NOT NULL,
sales_by_payment_sum_price / sales_by_payment, NULL)) AS
`sale_price`) AS `sale_price`, (
SELECT SUM(income_sum_price * 0.62) AS `our_percent`) AS
`our_percent`, (
SELECT SUM(IFNULL(income_sum_price,0) * 0.25) AS
`cost_price_income`) AS `cost_price_select`, (
SELECT SUM(IFNULL(sales_by_payment_sum_price,0) -
(IFNULL(income_sum_price,0) * 0.25)) AS `profit`) AS `profit`, (
SELECT SUM(IF(income IS NOT NULL, (sales_by_payment / income) *
100, 0)) AS `sales_from_income`) AS `sales_from_income`, (
SELECT (SUM(sales_by_payment) / SUM(return_before_payment)) * 100 AS
`returns_buyout`) AS `returns_buyout`, (
SELECT SUM(return_before_payment) / SUM(ordered) * 100 AS `returns`) AS
`returns`, (
SELECT SUM(sales_by_payment) / SUM(ordered) * 100 AS `buyout`) AS
`buyout`, (
SELECT SUM(IFNULL(income,0) - IFNULL(sales_by_payment,0) +
IFNULL(`return`,0)) AS `total`) AS `total`, (
SELECT (SUM(IFNULL(income,0)) - SUM(IFNULL(stock,0)) -
SUM(IFNULL(`sales_by_payment`,0)) + SUM(IFNULL(`return`,0))) AS
`in_the_way`) AS `in_the_way`
FROM `wildberries` AS `w`
WHERE `from` >= '2016-02-01' AND `end` <= '2017-05-04'
GROUP BY `article`
ORDER BY `article` DESC
LIMIT 20 OFFSET 0) AS `subt`
GROUP BY DAY(`from`)
ORDER BY `from` ASC
If dates range are between one year, all works fine. But if i use different years, it returns only one row.
Could anyone give me advice - why is it happen and how should i modify query?
Table scheme is
CREATE TABLE `wildberries` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`brand` VARCHAR(50) NULL DEFAULT NULL,
`subject` VARCHAR(50) NULL DEFAULT NULL,
`article` VARCHAR(50) NULL DEFAULT NULL,
`size` VARCHAR(50) NULL DEFAULT NULL,
`income` VARCHAR(50) NULL DEFAULT NULL,
`income_sum_price` VARCHAR(50) NULL DEFAULT NULL,
`ordered` VARCHAR(50) NULL DEFAULT NULL,
`ordered_sum_price` VARCHAR(50) NULL DEFAULT NULL,
`ordered_max_by_day` VARCHAR(50) NULL DEFAULT NULL,
`return_before_payment` VARCHAR(50) NULL DEFAULT NULL,
`return_before_payment_sum_price` VARCHAR(50) NULL DEFAULT NULL,
`sales_by_payment` VARCHAR(50) NULL DEFAULT NULL,
`sales_by_payment_sum_price` VARCHAR(50) NULL DEFAULT NULL,
`return` VARCHAR(50) NULL DEFAULT NULL,
`return_sum_price` VARCHAR(50) NULL DEFAULT NULL,
`stock` VARCHAR(50) NULL DEFAULT NULL,
`source_file` VARCHAR(50) NULL DEFAULT NULL,
`from` DATE NULL DEFAULT NULL,
`end` DATE NULL DEFAULT NULL,
PRIMARY KEY (`id`),
INDEX `article` (`article`)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB;
In your subquery you group by column article, but you select column from. You don't tell the DBMS which of the article's froms you want to see. This is invalid according to the SQL standard, but MySQL lets this slip and gives you one of the article's froms arbitrarily chosen.
So for the first 20 articles you select rather random dates.
In your main query you group by these dates' days parts. This can result in 1 to 20 rows and is based on coincidence (i.e. how the records happen to be stored on disk at that moment and how the DBMS retrieves them).

mysql query takes 4 min to execute

Table 1.
CREATE TABLE `admin_users` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`branch_id` int(11) DEFAULT '0',
`landingpage` int(11) DEFAULT '8',
`user_role_id` int(11) DEFAULT '0',
`user_parent_role` int(11) DEFAULT '0',
`bank_branch_id` int(11) DEFAULT '0',
`status` enum('1','0') COLLATE utf8_unicode_ci DEFAULT '1',
`firstname` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`lastname` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
PRIMARY KEY (`id`), KEY `user_role_id` (`user_role_id`)
) ENGINE=InnoDB AUTO_INCREMENT=281 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci CHECKSUM=1 DELAY_KEY_WRITE=1 ROW_FORMAT=DYNAMIC COMMENT='الموظفين';
Table 2.
CREATE TABLE `application_activity` (
`activityid` bigint(11) NOT NULL AUTO_INCREMENT,
`dataid` text,
`datatable` varchar(255) DEFAULT NULL,
`userid` int(11) DEFAULT '0',
`activitytype` char(1) DEFAULT 'I',
`activitytime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`activityip` varchar(15) DEFAULT NULL,
`activitydevice` text,
PRIMARY KEY (`activityid`)) ENGINE=MyISAM AUTO_INCREMENT=152862 DEFAULT CHARSET=utf8 COMMENT='نشاط التطبيق';
Query I am executing.
SELECT admin_users.`firstname`,admin_users.`lastname`,admin_users.`id`, branches.`branch_name`,
(SELECT COUNT(activityid) FROM application_activity WHERE userid=admin_users.`id`) AS cnt,
(SELECT activitytype FROM application_activity WHERE userid=admin_users.`id` ORDER BY activityid DESC LIMIT 0,1) AS activitytype,
(SELECT datatable FROM application_activity WHERE userid=admin_users.`id` ORDER BY activityid DESC LIMIT 0,1) AS datatable,
(SELECT activitytime FROM application_activity WHERE userid=admin_users.`id` ORDER BY activityid DESC LIMIT 0,1) AS activitytime
FROM admin_users
JOIN branches ON branches.`branch_id`=admin_users.`branch_id`
HAVING cnt > 0
ORDER BY cnt DESC
Table 1 have 100 records of users and Table 2 have more then 100k records of application activity.
when i execute query it will take 4min for giving result.
For this query:
This is your query:
SELECT au.`firstname`, au.`lastname`, au.`id`, b.`branch_name`,
(SELECT COUNT(*) FROM application_activity aa WHERE aa.userid = admin_users.`id`) AS cnt,
(SELECT aa.activitytype FROM application_activity aa WHERE aa.userid = au.`id` ORDER BY aa.activityid DESC LIMIT 0,1) AS activitytype,
(SELECT aa.datatable FROM application_activity aa WHERE aa.userid = au.`id` ORDER BY aa.activityid DESC LIMIT 0,1) AS datatable,
(SELECT aa.activitytime FROM application_activity aa WHERE aa.userid = au.id` ORDER BY aa.activityid DESC LIMIT 0,1) AS activitytime
FROM admin_users au JOIN
branches b
ON b.`branch_id` = au.`branch_id`
HAVING cnt > 0
ORDER BY cnt DESC;
You need appropriate indexes. One is on branches(branch_id) -- but you might have this already.
The second is application_activity(userid, activityid).
I strongly recommend that when all columns in correlated subqueries be qualified with the table alias.

MYSQL QUERY : Select 1 rows photo from table for each album

I have a table with records and it has a table called gallery. I have inserted too many photo and I want to select only 2 random photo from each gallery.
here my structured
CREATE TABLE IF NOT EXISTS `gallery` (
`gallery_id` int(11) NOT NULL,
`gallery_name` varchar(100) NOT NULL,
`gallery_name_seo` varchar(120) NOT NULL,
`gallery_client` varchar(100) NOT NULL,
`gallery_date` date NOT NULL,
`gallery_type` int(2) NOT NULL,
`gallery_desc` text,
`gallery_publish` char(1) NOT NULL DEFAULT 'N' COMMENT 'Y = Yes & N = No',
`gallery_added` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`deleted` int(11) NOT NULL DEFAULT '0'
) ENGINE=MyISAM AUTO_INCREMENT=3 DEFAULT CHARSET=latin1;
and here another table
CREATE TABLE IF NOT EXISTS `gallery_photo` (
`id` int(10) NOT NULL,
`id_gallery` int(10) NOT NULL,
`file_name` varchar(255) NOT NULL,
`file_added` date NOT NULL,
`deleted` smallint(6) NOT NULL DEFAULT '0'
) ENGINE=InnoDB AUTO_INCREMENT=24 DEFAULT CHARSET=latin1;
acctually there many example here but i hard to understand,
how to create query from my problem.?
thanks
The following query would give you 1 random photo per id_gallery:
SELECT *
FROM (SELECT * FROM `gallery_photo` ORDER BY RAND()) as `rand_photos`
GROUP BY rand_photos.id_gallery
You could UNION it with itself to get 2 random photos for each gallery:
SELECT *
FROM (SELECT * FROM `gallery_photo` ORDER BY RAND()) as `rand_photo1`
GROUP BY rand_photo1.id_gallery
UNION
SELECT *
FROM (SELECT * FROM `gallery_photo` ORDER BY RAND()) as `rand_photo2`
GROUP BY rand_photo2.id_gallery
ORDER BY id_gallery

MySQL Order by subquery column

I have problem with sql query. The idea is to select all loans that are after payment (status 1/2/3) between 8 and 21 days with calculated value from payment_day til now.
I have already done some query but can't use columns days_after_payment and days_after_part_payment in WHERE section. I would like to have one column like days_after_payment based on loan type.
SELECT l.*,
(SELECT SUM(`value`) FROM `loan_part` WHERE `loan_id` = l.id AND `paid`=0) AS left_to_pay,
-(DATEDIFF((SELECT date FROM `loan_part` WHERE `loan_id` = l.id AND `paid`=0 AND `date`<CURDATE() ORDER BY `date` LIMIT 1), NOW())) AS days_after_part_payment,
-(DATEDIFF(l.payment_date, NOW())) AS days_after_payment
FROM loan l
WHERE (l.type=1 or l.type=2) AND (l.status=1 OR l.status=2 OR l.status=3)
GROUP BY l.client_id
ORDER BY
CASE l.type
WHEN 1 THEN days_after_payment
WHEN 2 THEN days_after_part_payment
ELSE 1 END
ASC
CREATE TABLE IF NOT EXISTS `loan` (
`id` int(11) NOT NULL,
`value` int(11) NOT NULL,
`client_id` int(11) NOT NULL,
`status` int(11) NOT NULL,
`type` int(11) NOT NULL,
`payment_date` date DEFAULT NULL
) ENGINE=MyISAM AUTO_INCREMENT=2068 DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `loan_part` (
`id` int(10) unsigned NOT NULL,
`loan_id` int(11) NOT NULL,
`value` float NOT NULL,
`date` date DEFAULT NULL,
`paid` tinyint(1) NOT NULL DEFAULT '0'
) ENGINE=MyISAM AUTO_INCREMENT=1751 DEFAULT CHARSET=utf8;
Update1 : I had to cut unnecessary columns and rewrite it into English from my native language.
ORDER BY 7
"7" means the 7th field in the SELECT. That works for GROUP BY also. I had to see the table definition to count how many in l.*.
How come id is not declared AUTO_INCREMENT?