This may not be possible ;^)
I'm trying to pull together billing and performance data from separate client dbs. The "core" db has a table like so:
client_id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
client_db_name VARCHAR(100),
...
Each client_db has a table, orders, with columns order_date and order_total.
Conceptually, I'd like to be able to use the client_db_name in a query:
SELECT SUM(order_total) AS sales
FROM {client_db_name}.orders AS o
WHERE o.order_date LIKE '2021%'
Questions:
is this even possible?
if so, how would I JOIN this query? What would the ON be?
Many thanks!
No interpolation.
A Stored procedure might be able to perform the interpolation via CONCAT, PREPARE and EXECUTE.
Wouldn't it be better the have all the customers in the same table? That would make it all easier.
You can make a dynamic query, a query that is the result of another query.
SELECT GROUP_CONCAT(query_piece SEPARATOR ' UNION ALL ')
FROM (SELECT CONCAT("SELECT '", client_db_name, "' AS client, SUM(order_total) AS sales FROM ", client_db_name, '.orders o WHERE YEAR(o.order_date) = 2021') AS query_piece
FROM core.clients) AS sq
My query will return a dynamic query like this (I have two clients into core.clients table: a and b):
SELECT 'a' AS client, SUM(order_total) AS sales FROM a.orders o WHERE YEAR(o.order_date) = 2021
UNION ALL
SELECT 'b' AS client, SUM(order_total) AS sales FROM b.orders o WHERE YEAR(o.order_date) = 2021
The dynamic query will return something like this:
client
sales
a
50.00
b
100.00
Related
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).
I have two tables orders and company. Company table contains unique company id and company name.
Orders table has two column, one is orderid and other is companyIDs. CompanyIds can be multiple comma separated values.
I am using following query to get the company name corresponding to each company id of orders table.
SELECT
(SELECT GROUP_CONCAT(cmp.cmpny_name)
FROM company cmp
WHERE FIND_IN_SET(cmp.CompanyID, odr.companyIDs)
) AS company
FROM orders odr
It works perfectly fine in Mysql but not in sql server as these keywords are not supported in sql server and I haven' worked on sql server much so please help me to find correct way to accomplish this.
Thanks
On search, I have got some keywords like stuff for group concat but not able to use properly. Not able to find an equivalent of the find_in_set for sql server.
SELECT
(SELECT GROUP_CONCAT(cmp.cmpny_name)
FROM company cmp
WHERE FIND_IN_SET(cmp.CompanyID, odr.companyIDs)
) AS company
FROM orders odr
Not working in sql server
This should work with SQL server 2016, if its lower split function should be written in a different way
SELECT
STUFF( (
SELECT ',' + cmp.cmpny_name
FROM company cmp
WHERE cmp.CompanyID IN (SELECT value FROM STRING_SPLIT (odr.companyIDs,','))
FOR XML PATH('')), 1, 1, NULL) AS company
FROM orders odr
if SQL server 2017
SELECT
(SELECT STRING_AGG(cmp.cmpny_name)
FROM company cmp
WHERE cmp.CompanyID in (SELECT value FROM string_split (odr.companyIDs,','))
) AS company
FROM orders odr
GroupConcat can be replaced by STRING_AGG()
and you can replace also Find_In_Set by CONCAT(',',yourVariable,',') LIKE CONCAT('%,',youOtherVariable,',%')
So I think this might help you
SELECT
(SELECT STRING_AGG(cmp.cmpny_name,',')
FROM company cmp
WHERE CONCAT(',',cmp.CompanyID,',') LIKE CONCAT('%,',odr.companyIDs,',%')
) AS company
FROM orders odr
Ref:
FIND_IN_SET() equivalent in SQL Server
https://database.guide/the-sql-server-equivalent-to-group_concat/
It's a bit difficult to explain the situation, but currently I'm generating massive unions to accomplish this. They look at bit like:
(
SELECT
ipaddress
FROM post
WHERE ipaddress = 'someipaddress'
AND userid NOT IN (1, {$postinfo['userid']}, {$vbulletin->options['sdwikipostuserid']})
LIMIT 1
)
UNION
(
SELECT
ipaddress
FROM post
WHERE ipaddress = 'someotheripaddress'
AND userid NOT IN (1, {$postinfo['userid']}, {$vbulletin->options['sdwikipostuserid']})
LIMIT 1
)
These get huge fast, but seem to be the fastest way for me to accomplish this right now. I've tried refactoring it to something like:
SELECT
ipaddress
FROM post
WHERE ipaddress in ('all ips', .....)
AND userid NOT IN (1, {$postinfo['userid']}, {$vbulletin->options['sdwikipostuserid']})
GROUP BY ipaddress
But this is around x5 slower than the massive union statement. The big issue is that the post table is huuuuuge, so the refactored SQL is forced to look through the entire table where each union statement can break after finding a single instance. Is there any way to specify the SQL to break on finding the first unique group?
Anyone have tips on how to refactor the huge union statement above into something cleaner?
You can write the query like this:
select i.ipaddress
from (select 'someipaddress' as ipaddress union all
select 'someotheripaddress'
) i
where exists (select 1
from posts p
where p.ipaddress = i.ipaddress and
p.userid NOT IN (1, {$postinfo['userid']}, {$vbulletin->options['sdwikipostuserid']})
);
This is optimized with an index on posts(ipaddress, userid) -- one index, two columns.
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
I want to add some dynamic content in from clause based on one particular column value.
is it possible?
For Example,
SELECT BILL.BILL_NO AS BILLNO,
IF(BILL.PATIENT_ID IS NULL,"CUS.CUSTOMERNAME AS NAME","PAT.PATIENTNAME AS NAME")
FROM
BILL_PATIENT_BILL AS BILL
LEFT JOIN IF(BILL.PATIENT_ID IS NULL," RT_TICKET_CUSTOMER AS CUS ON BILL.CUSTOMER_ID=CUS.ID"," RT_TICKET_PATIENT AS PAT ON BILL.PATIENT_ID=PAT.ID")
But This query is not working.
Here
BILL_PATIENT_BILL table is a common table.
It can have either PATIENT_ID or CUSTOMER_ID. If a particular record has PATIENT_ID i want PATIENTNAME in RT_TICKET_PATIENT as NAME OtherWise it will hold CUSTOMER_ID. If it is i want CUSTOMERNAME as NAME.
Here I m sure That BILL_PATIENT_BILL must have either PATIENT_ID or CUSTOMER_ID.
Can anyone help me?
You can also use IF() to select the right values instead of constructing your query from strings:
SELECT
BILL.BILL_NO AS BILLNO,
IF( BILL.PATIENT_ID IS NULL, cus.CUSTOMERNAME, pat.PATIENTNAME ) AS NAME
FROM
BILL_PATIENT_BILL AS BILL
LEFT JOIN RT_TICKET_CUSTOMER cus ON BILL.CUSTOMER_ID = cus.ID
LEFT JOIN RT_TICKET_PATIENT pat ON BILL.PATIENT_ID = pat.ID
However, it would also be possible to PREPARE a statement from strings and EXECUTE it but this technique is prone to SQL injections, i can only disadvise to do so:
read here: Is it possible to execute a string in MySQL?