substitute of count(*) OVER () in mysql - mysql

this is my SQL server query
` Select top 8
count(id) OVER () as speccount,
(SELECT count(*) From Profile_Master pm WHERE CONCAT(pm.fname , pm.lname) LIKE '%'+#keyword+'%' and
(select Top 1 city from DAddress_Master where profileid=pm.id)=#city) as drcount,
(SELECT count(*) From DAddress_Master dam WHERE dam.city=#city and dam.clinicname LIKE '%'+#keyword+'%') as cliniccount,
specialization AS name,
id as id,
'Specialization' as type,
'' as drspec
From Specialization_Master
Where specialization LIKE '%'+#keyword+'%'`
actually part of my whole query. now i have to convert this query into mysql, which not that much big deal, but can some one tell substitute of count(*) OVER () in mysql?
I came across to this functions.
SELECT SQL_CALC_FOUND_ROWS
and SELECT FOUND_ROWS();
but is there another way??

The easiest way is probably a subquery:
select (select count(*) from Specialization where specialization LIKE '%'+#keyword+'%'`
) as speccnt
Note: if you are switching databases and you are using functionality such as window functions, you might consider Postgres rather than MySQL, because Postgres supports window functions.

Related

SQL - Nested query optimization

How can I optimize this query SQL?
CREATE TABLE table1 AS
SELECT * FROM temp
WHERE Birth_Place IN
(SELECT c.DES_COM
FROM tableCom AS c
WHERE c.COD_PROV IS NULL)
ORDER BY Cod, Birth_Date
I think that the problem is the IN clause
First of all it's not quite valid SQL, since you are selecting and sorting by columns that are not part of the group. What you want to do is called "select top N in group", check out Select first row in each GROUP BY group?
Your query doesn't make sense, because you have SELECT * with GROUP BY. Ignoring that, I would recommend writing the query as:
SELECT t.*
FROM temp t
WHERE EXISTS (SELECT 1
FROM tableCom c
WHERE t.Birth_Place = c.DES_COM AND
c.COD_PROV IS NULL
)
ORDER BY Cod, Birth_Date;
For this, I recommend an index on tableCom(desc_com, cod_prov). Your database might also be able to use an an index on temp(cod, birth_date, birthplace).

CTE recursive query in select statement

I have two MySQL server version 8.0, one for local development and another on an Heroku Instance, more precisely on Heroku i'm using a service called JAWSDB.
For my project I have to use the following CTE query, because the structure of the table tree_structure is hierarchical.
The purpose of the query is that for every row in tree_structure I have to get all of its child, and then count how many user in user_roles table are present in that particular row and its child.
SELECT mtr.id,
mtr.parent_id,
mtr.name,
mtr.manager_id,
CONCAT(users.nome, ' ', users.cognome) as resp_name,
(
with recursive cte (id, name, parent_id) as (
select id,
name,
parent_id
from tree_structure as tr_rec
where tr_rec.parent_id = mtr.id
and tr_rec.session_id = '2018'
union all
select tr.id,
tr.name,
tr.parent_id
from tree_structure as tr
inner join cte
on tr.parent_id = cte.id
WHERE tr.session_id = '2018'
)
select count(distinct (user_id))
from user_roles as ur_count
where ur_count.structure_id in (select distinct(id) from cte)
) as utenti
FROM tree_structure as mtr
LEFT JOIN users ON mtr.manager_id = users.id
WHERE level = 0
The problems is that on my local server it works whereas on the heroku instance it gaves me the following error:
unknow columns mtr.id in where clause.
Has someone any ideas of what is causing this error?
Thanks in advance and sorry for my bad english.
You have an ambiguous table reference in the CTE:
SELECT
....
(with recursive cte (id, name, parent_id) as (
....
from tree_structure as tr_rec -- here you have aliased the table
where tr_rec.id = tree_structure.id -- here you refer to the table and its alias
and tr_rec.session_id = '2018'
union all
....
)
....
) as utenti
....
Table tree_structure is used in the subselect and in the outermost select. The good practice is to make an unique alias for every table reference you have used.
Also you have a typo in the condition that should check self-referencing of the hierarcy root node:
where tr_rec.id = tr_rec.parent_id
and tr_rec.session_id = '2018'
OK guys I found out why the query was wrong. Apparently since MySQL version 8.0.14 they introduced support for using external parameters within subqueries.
My local version was 8.0.16 but the online version was 8.0.11 so because of this my query didn't work.

Recursive CTEs to pull BOM (Bill of Material)

I need some assistance or pointer on CTEs.
I am trying to extract Bill of Material and I have used CTEs query. The query works good and it pulls all the data. My struggle is there are lot of parts where the parts has new version on different levels and I want to grab new versions only. Currently my query grabs everything. I have a version column.
I tried few different things like trying to utilize max function within CTEs but I got an error saying group by, having cannot be part of recursive ctes.
Also, I tried using subquery but I didnt get the right result.
WITH BOM (
Parent
,Child
,Qty
,Childrev
,LEVEL
,sort
)
AS (
SELECT Parent
,cast(RTRIM(Child) AS NVARCHAR(max))
,Qty
,Childrev
,0 AS LEVEL
,cast(RTRIM(Child) AS NVARCHAR(max))
FROM Bomtable
UNION ALL
SELECT BOM.Parent
,cast(RTRIM(Bomtable.Child) AS NVARCHAR(max))
,Bomtable.Qty
,BOM.Childrev
,LEVEL + 1
,CAST(BOM.Sort + '..... ' + RTRIM(Bomtable.Child) AS NVARCHAR(max))
FROM BOM
INNER JOIN Bomtable ON Bomtable.Parent = BOM.Child
WHERE BOM.Parent = main product
ORDER BY SORT
)
I know I do not fully understand your data model. However, try replacing your BOM and BomTable tables with a derived table like this which will give you one row for each Child record with the greatest Childrev value without using a GROUP BY.
SELECT *
FROM (
SELECT *
, ROW_NUMBER() OVER (PARTITION BY Child ORDER BY Childrev DESC) AS ROW_NBR
FROM BOM
) AS x
WHERE x.ROW_NBR = 1;
Here is the documentation for the the OVER Clause.
Noel

SQL Server 2008 - Avoiding a foreach loop

I am trying desperately to avoid a foreach situation in SQL Server 2008 (my background is in c#).
Basically, I have a list of SKUs. For each SKU in the list, I need to perform some calculations that determine if that particular SKU will be displayed on the web.
To get my list of SKUs, I use this:
SELECT Feed.StyleCode as SKU
FROM [eCommerce].[dbo].[BABW_ItemFeed] as Feed
WHERE Feed.ProductDefinition = 'Kit'
Returning this:
And to calculate each SKUs fields, I've been using this:
DECLARE #SKU AS varchar(50)
SET #SKU= '11993_16559_16227'
SELECT
#SKU as SKU,
0 AS Quantity,
MIN(ISNULL(Sending.IsActive, 'WEBNO')) AS IsActive,
MAX(ISNULL(Sending.IsDiscontinued, 1)) AS IsDiscontinued
FROM
(
SELECT * FROM [eCommerce].[dbo].[Split] (
#SKU
,'_')
) AS SplitSkus
LEFT JOIN #SkusToSend AS Sending
ON Sending.SKU = SplitSkus.items
Returning this:
Now I need to synch the two tables together, removing the #SKU declaration. I don't think I'm able to use a UNION to do this, because the second function requires fore-knowledge of the SKU it will be processing... and a JOIN would require something to join on, which I don't really have. Is there some function I'm not familiar with that I can use to create a complete table of SKUs in one go without a looping mechanism?
Try a CROSS APPLY... which will execute your UDF for each row in BABW_ItemFeed:
SELECT
Feed.StyleCode as SKU,
COUNT(*) AS Quantity,
MIN(ISNULL(Sending.IsActive, 'WEBNO')) AS IsActive,
MAX(ISNULL(Sending.IsDiscontinued, 1)) AS IsDiscontinued
FROM
[eCommerce].[dbo].[BABW_ItemFeed] as Feed
CROSS APPLY [eCommerce].[dbo].[Split] (Feed.StyleCode, '_') AS SplitSkus
LEFT JOIN #SkusToSend AS Sending
ON Sending.SKU = SplitSkus.items
WHERE
Feed.ProductDefinition = 'Kit'
GROUP BY
Feed.StyleCode
Stop using Min() and Max()...or else, pull SKU (don't use the parameter in the SELECT).
Try This:
SELECT
SKU,
0 AS Quantity,
MIN(ISNULL(Sending.IsActive, 'WEBNO')) AS IsActive,
MAX(ISNULL(Sending.IsDiscontinued, 1)) AS IsDiscontinued
FROM
(
SELECT [eCommerce].[dbo].[Split] (Feed.StyleCode,'_') as SKU
FROM [eCommerce].[dbo].[BABW_ItemFeed] as Feed
WHERE Feed.ProductDefinition = 'Kit'
) AS SplitSkus
LEFT JOIN #SkusToSend AS Sending
ON Sending.SKU = SplitSkus.items

How to transform a MSSQL CTE query to MySQL?

in my MySQL schema, I have the category(id, parentid, name) table
In the MSSQL, I have that CTE query (to build a category tree from the bottom up for a supplied category ID:
with CTE (id, pid, name)
as
(
select id, parentid as pid,name
from category
where id = 197
union all
select CTE.pid as id , category.parentid as pid, category.name
from CTE
inner join category
on category.id = CTE.pid
)
select * from CTE
How to 'transform' that query to MySQL ?
Unfortunately MySQL doesn't support CTE (Common Table Expressions). This is long overdue IMO. Often, you can just use a subquery instead, but this particular CTE is recursive: it refers to itself inside the query. Recursive CTE's are extremely useful for hierarchical data, but again: MySql doesn't support them at all. You have to implement a stored procedure to get the same results.
A previous answer of mine should provide a good starting point:
Generating Depth based tree from Hierarchical Data in MySQL (no CTEs)
Thankfully it's not necessary anymore, as MySQL starting from 8.0.1 supports CTE.
unfortunately MYSQl or XAMPP(MARIADB) mysql doesnot support CTEs(COMMON TABLE EXPRESSIONS),
for the same you will have to use nested queries.
for more information click on the below link:-
https://mariadb.com/kb/en/library/with/
Please check what version of MySQL you have using SELECT VERSION();
If it is 8 or above you can then proceed further with my comment.
With MySQL 8.0, MariaDB 10.2, and later versions, you can use recursive CTEs:
WITH RECURSIVE CTE (id, pid, name) AS (
select id, parentid as pid,name
from category
where id = 197
union all
select CTE.pid as id , category.parentid as pid, category.name
from CTE
inner join category
on category.id = CTE.pid
)
select * from CTE ;
Note that CTEs are limited by cte_max_recursion_depth (default 1000, max 4,294,967,295 (2³²−1)) in MySQL and by max_recursive_iterations (default 4,294,967,295) in MariaDB.
You can increase the limit by executing:
SET cte_max_recursion_depth = 4294967295;
It will only affect your current session and won't be persisted.