I am trying to set myItemId so that I can use it in the concat query. Everything works fine until I add this row
SET myItemID = (SELECT * FROM items i WHERE i.name LIKE '%KW PRE FREE COOLING%');
It then gives me an error of
Operand should contain 1 column(s)
Here is the query that I am working with
CREATE PROCEDURE reportFreeCoolingTempTable (
IN fromDate VARCHAR (50),
IN toDate VARCHAR (50),
IN timeZone VARCHAR (50)
)
BEGIN
DECLARE startDate VARCHAR (50);
DECLARE endDate VARCHAR (50);
DECLARE mylogID INT;
DECLARE myItemID int;
SET startDate = FROM_UNIXTIME(fromDate/1000);
SET endDate = FROM_UNIXTIME(toDate/1000);
SET mylogID = (SELECT logID FROM logs WHERE details LIKE 'FCT%' LIMIT 1);
SET myItemID = (SELECT * FROM items i WHERE i.name LIKE '%KW PRE FREE COOLING%');
SET #sql = NULL;
SET #sql = NULL;
SET #sql = CONCAT(
'SELECT #row:=#row+1 as rownum,
a.logid ,
L1.recordId,
L2.recordId as next_recordId,
L1.completed,
L2.completed as next_completed,
L1.activityId,
L2.activityId as next_activityId,
IF(L1.activityId = L2.activityId,1,NULL) as isError,
TIME_TO_SEC(TIMEDIFF(L2.completed, L1.completed)) / 3600 AS coolingHours,
((L1.item31985 - L1.item31987) * (time_to_sec(timediff(L2.completed, L1.completed)))) / 3600 AS kwDifference,
((L1.item31985 - L1.item31987) * (substr(l.details, instr(l.details , '':'' ) +1))) AS cost,
( (((L1.item31985 - L1.item31987) * (substr(l.details, instr(l.details , '':'' ) +1)))
*(time_to_sec(timediff(L2.completed, L1.completed)) / 3600))) AS costT,
time_to_sec(timediff(''', endDate, ''', ''', startDate, ''')) / 3600 AS totalTimeRange,
CONVERT_TZ(''', startDate, ''', ''UTC'', ''', timeZone, ''') AS startingDate,
CONVERT_TZ(''', endDate, ''', ''UTC'', ''', timeZone, ''') AS endingDate,
DATABASE() AS databaseName
FROM
(SELECT #row:=0)R,
(SELECT T1.completed,
(SELECT MIN(completed)
FROM log1644
WHERE completed > T1.completed) AS next_completed
FROM log',mylogID, ' T1
ORDER BY T1.completed
)TimeOrder
LEFT JOIN log', mylogID, ' L1 ON (L1.completed = TimeOrder.completed)
LEFT JOIN log', mylogID, ' L2 ON (L2.completed = TimeOrder.next_completed)
LEFT JOIN activities a ON L1.activityId = a.activityId
LEFT JOIN logs l ON a.logId = l.logId
Left Join items i ON l.logId = i.logId AND i.name LIKE ''%KW%''
WHERE i.itemID = 31985
AND L1.completed BETWEEN ''', startDate, ''' AND ''', endDate, '''
ORDER BY L1.completed');
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END //
DELIMITER ;
Error itself explains (operands should contain 1 column) you need to select the single column from the query in order to set myItemID ,you are selecting all the columns from the items try this
SET myItemID = (SELECT id FROM items i WHERE i.name LIKE '%KW PRE FREE COOLING%' LIMIT 1 );
I assume the you need to set the myItemID to the id column from items where you conditions matches.i have also added LIMIT 1 in order to avoid the error of subquery should return one result
The error is caused because the SET statement expects a single value to be returned from your subquery. Not only can it return multiple values (SELECT *), but it can potentially return multiple rows. Change your query to specify just the single column from your subquery that you want to assign to myItemId, and ensure that it can return only 1 row - like this:
SET myItemID = (SELECT TOP 1 [itemIdColumnName] FROM items i WHERE i.name LIKE '%KW PRE FREE COOLING%');
The 'operand' in your case is "myItemID". It can only hold ONE value. Your SELECT statement returns all the rows in the table (multiple columns). You need to select only the 1 column that represents the ID you are trying to obtain.
Related
I have a query to report some data :
select r.m_id,
count(distinct case when r.sal = '1val' then r.login end) as 1val,
count(distinct case when r.sal = '2val' then r.login end) as 2val,
count(distinct case when r.sal = '3val' then r.login end) as 3val,
...
from read_log r
inner join mes m on m.id = r.m_id
where
YEAR(m.send_date) = YEAR(curdate())
group by r.m_id
r.sal value in count(distinct case when r.sal = '1val' then r.login end) as 1val only changes. Finally it shows results in each column for every r.sal. There are currently over 80 diffrent r.sal and its growing.
My question is:
It is possible to take value for r.sal from another table?
Like new table sal with this 1val, 2val, 3val, 4val, 5val etc...?
Maybe loop or something like that:
count(distinct case when r.sal = (select val from sal) then r.login end)
(I know its wrong but maybe it will illustrate it better)
count(distinct case... is great to show data for each r.sal value in the other column but maybe is another way to achieve that...
CREATE TABLE sal_table (sal CHAR(4));
INSERT INTO sal_table VALUES ('1val'), ('2val'), ... ;
CREATE PROCEDURE get_data ()
BEGIN
SELECT CONCAT (
'select r.m_id, ',
GROUP_CONCAT(
CONCAT(
'count(distinct case when r.sal = ''',
sal,
''' then r.login end) as `',
sal,
'`'
)
),
' from read_log r ',
'inner join mes m on m.id = r.m_id ',
'where YEAR(m.send_date) = YEAR(curdate()) ',
'group by r.m_id'
)
INTO #sql
FROM sal_table;
PREPARE stmt FROM #sql;
EXECUTE stmt;
DROP PREPARE stmt;
END
https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=af55c52aca3280410fba1f3a453aab09
PS. Recommended edition: WHERE m.send_date >= DATE_FORMAT(CURRENT_DATE, '%Y-01-01') AND m.send_date < DATE_FORMAT(CURRENT_DATE + INTERVAL 1 YEAR, '%Y-01-01'). Such condition is sargable rather than your one.
Looking for a way to return a variable that can be used inside a IN-operator.
My current result returns: 1,2,3,
but I guess the variable should be more like this: '1','2','3' to be able to use it.
Is this possible?
Or should I try something else like explode, save the query,...
-- init vars
SET #export_date = '2022-06-20';
SET #order_ids = '';
-- Tasks on given day
SELECT * FROM tasks WHERE task_execution_date = #export_date;
-- method 1
SET #order_ids = (SELECT GROUP_CONCAT(DISTINCT task_order SEPARATOR ',' ) FROM tasks WHERE task_execution_date = #export_date);
SELECT #order_ids; -- "1,2,3"
-- method 2
SET #order_ids = (SELECT GROUP_CONCAT(DISTINCT '' + cast( task_order AS CHAR(50)) +'' ) FROM tasks WHERE task_execution_date = #export_date);
SELECT #order_ids; -- "1,2,3"
-- method 3
SET #order_ids = (SELECT GROUP_CONCAT( DISTINCT + '\'' + CAST(task_order AS CHAR (100)) + '\'') FROM tasks WHERE task_execution_date = #export_date);
SELECT #order_ids; -- "1,2,3"
-- Orders by tasks
SELECT * from orders WHERE ordr_id IN (#order_ids); -- returns only one result
-- SELECT * from orders WHERE ordr_id IN #order_ids; -- error
SELECT * from orders WHERE ordr_id IN ('1', '2', '3'); -- works
SELECT * from orders WHERE ordr_id IN (SELECT DISTINCT task_order FROM tasks WHERE task_execution_date = #export_date); -- works
-- Also needed:
-- goods by orders
-- good_adrs by goods
If You really, really, I mean REALLY know that these variables can't be evil, then You can build and execute raw query:
SET #export_date = '2022-06-20';
SET #order_ids = (SELECT GROUP_CONCAT(DISTINCT task_order SEPARATOR ',' ) FROM tasks WHERE task_execution_date = #export_date);
SET #query = CONCAT('SELECT * from orders WHERE ordr_id IN (', #order_ids, ');');
PREPARE stmt FROM #query;
EXECUTE stmt;
I want to run a query that shows me all columns from all tables in a database with the datatype varchar and a maximum length of 8000 characters.
This is my code so far.
DECLARE #tabs VARCHAR(MAX);
SET #tabs =
(
SELECT STUFF(( SELECT DISTINCT ',' + [TABLE_NAME]
FROM [DB-Test].INFORMATION_SCHEMA.COLUMNS
WHERE DATA_TYPE = 'VARCHAR' AND
CHARACTER_MAXIMUM_LENGTH = 8000
FOR XML PATH('')), 1, 1, '')
);
DECLARE #cols VARCHAR(MAX)
SET #cols =
(
SELECT STUFF(( SELECT DISTINCT ',' + [TABLE_NAME] + '.' + [COLUMN_NAME]
FROM [DB-Test].INFORMATION_SCHEMA.COLUMNS
WHERE DATA_TYPE = 'VARCHAR' AND
CHARACTER_MAXIMUM_LENGTH = 8000
FOR XML PATH('')), 1, 1, '')
);
DECLARE #query VARCHAR(MAX) = 'SELECT ' + #cols + ' FROM ' + #tabs
EXEC sp_sqlexec #query
When I run the query I get all the column names, but not the values in the columns. It's empty. No 'NULL'-values. As if #cols is interpreted as simple string maybe.
Why?
(When I read out #cols and #tabs they are correct.)
I guess there is one table available in your database which have column with VARCHAR datatype and 8000 length but that table don't have any records. Try by including only those column and table which have at least one record available.
You can try below. Check it and let me know if it works.
DECLARE #tabs VARCHAR(MAX) = ''
; WITH CTE AS
(
SELECT DISTINCT TA.NAME TABLENAME
, SUM(PA.ROWS) OVER (PARTITION BY TA.NAME ) NOOFROW
FROM SYS.TABLES TA
INNER JOIN SYS.PARTITIONS PA ON PA.OBJECT_ID = TA.OBJECT_ID
INNER JOIN SYS.SCHEMAS SC ON TA.SCHEMA_ID = SC.SCHEMA_ID
WHERE TA.IS_MS_SHIPPED = 0 AND PA.INDEX_ID IN (1,0)
), TABLENAME AS
(
SELECT ITBL.[TABLE_NAME]
FROM INFORMATION_SCHEMA.COLUMNS ITBL
WHERE ITBL.DATA_TYPE = 'VARCHAR' AND
ITBL.CHARACTER_MAXIMUM_LENGTH = 8000
AND EXISTS(SELECT 1 FROM CTE WHERE CTE.TABLENAME = ITBL.TABLE_NAME AND CTE.NOOFROW > 0) -- To check no of record available in table
)
SELECT #tabs = #tabs+ISNULL(','+TABLE_NAME, '')
FROM TABLENAME
DECLARE #cols VARCHAR(MAX) = '';
; WITH CTE AS
(
SELECT DISTINCT TA.NAME TABLENAME
, SUM(PA.ROWS) OVER (PARTITION BY TA.NAME ) NOOFROW
FROM SYS.TABLES TA
INNER JOIN SYS.PARTITIONS PA ON PA.OBJECT_ID = TA.OBJECT_ID
INNER JOIN SYS.SCHEMAS SC ON TA.SCHEMA_ID = SC.SCHEMA_ID
WHERE TA.IS_MS_SHIPPED = 0 AND PA.INDEX_ID IN (1,0)
), TABLENAME AS
(
SELECT ITBL.[TABLE_NAME], ITBL.[COLUMN_NAME]
FROM INFORMATION_SCHEMA.COLUMNS ITBL
WHERE ITBL.DATA_TYPE = 'VARCHAR' AND
ITBL.CHARACTER_MAXIMUM_LENGTH = 8000
AND EXISTS(SELECT 1 FROM CTE WHERE CTE.TABLENAME = ITBL.TABLE_NAME AND CTE.NOOFROW > 0) -- To check no of record available in table
)
SELECT #cols = #cols+ISNULL(','+[TABLE_NAME]+'.'+[COLUMN_NAME], '')
FROM TABLENAME
IF LEN(#cols) > 0 AND LEN(#tabs) > 0
BEGIN
DECLARE #query VARCHAR(MAX) = 'SELECT ' + STUFF(#cols,1,1,'') + ' FROM ' + STUFF(#tabs,1,1, '')
EXEC sp_sqlexec #query
END
ELSE
BEGIN
PRINT 'No Column available with data where it''s datatype is VARCHAR and length is 8000'
END
I am writing a stored procedure for my business directory application. The browse listings form has a select menu that lets users order listings by certain fields. If the sortField parameter is not null, it should order by that column in the order specified by the sortOrder(asc or desc) parameter. If the sortField parameter is specified, then the sortOrder field will always be specified with it. I am getting an error that says "Check the syntax near IF sortField != NUL .... ELSE ORDER BY l.lis"
Here is my query:
CREATE PROCEDURE `ListingsRetrieve` (
IN listingId INT(15),
IN categoryID INT(15),
IN regionId INT(15),
IN memberId INT(15),
IN keywords VARCHAR(250),
IN filterDistance INT(3),
IN latitude DOUBLE,
IN longitude DOUBLE,
IN sortField VARCHAR(16),
IN sortOrder VARCHAR(16),
IN page INT(15),
IN perPage INT(3)
)
BEGIN
SELECT
l.listing_id AS id, l.member_id, l.category_id, l.banner_id, l.thumbnail_id, l.logo_id, l.title AS listing_title, l.description, l.address, l.city, l.zip, UNIX_TIMESTAMP(l.date_submitted) AS date_submitted, l.latitude, l.longitude,l.phone,l.website, l.phone, l.contact_email, l.facebook_url, l.twitter_url, l.slug AS listing_slug,
l.sunday_open, l.sunday_close, l.monday_open, l.monday_close, l.tuesday_open, l.tuesday_close, l.wednesday_open, l.wednesday_close, l.thursday_open, l.thursday_close, l.friday_open, l.friday_close, l.saturday_open, l.saturday_close,
( 6371 * acos( cos( radians(latitude) ) * cos( radians( l.latitude) ) * cos( radians( l.longitude ) - radians(longitude) ) + sin( radians(latitude) ) * sin( radians( l.latitude ) ) ) ) AS distance,
c.category_id AS cat_id, c.slug AS cat_slug, c.icon AS cat_icon,
r.region_id AS region_id, r.title AS region_title, r.slug AS region_slug, (FLOOR((AVG(rev.score)) * 2) / 2) AS stars,
(SELECT
AVG(FLOOR(AVG(rev.score) * 2) / 2)
FROM
reviews AS r
INNER JOIN
listings AS l ON r.review_listing_id = l.listing_id
) as totalAvg,
((COUNT(rev.review_id) / (COUNT(rev.review_id)+5)) * (FLOOR((AVG(rev.score)) * 2) / 2) + (5 / (COUNT(rev.review_id)+5)) * AVG(rev.score)) AS rating,
b.attachment_id AS banner_id, b.file_path AS banner_path,
t.attachment_id AS thumbnail_id, t.file_path AS thumbnail_path,
lgo.attachment_id AS logo_id, lgo.file_path AS logo_path,
CONCAT_WS('/', r.slug, c.slug, l.slug, l.listing_id) AS listing_uri
FROM listings AS l
LEFT JOIN categories AS c ON l.category_id = c.category_id
LEFT JOIN regions AS r ON l.region_id = r.region_id
LEFT JOIN reviews AS rev ON l.listing_id = rev.review_listing_id
LEFT JOIN attachments AS b ON l.banner_id = b.attachment_id
LEFT JOIN attachments AS t ON l.thumbnail_id = t.attachment_id
LEFT JOIN attachments AS lgo ON l.logo_id = lgo.attachment_id
WHERE (listingId IS NULL or l.listing_id = listingId) AND
(categoryId IS NULL or l.category_id = categoryId) AND
(regionId IS NULL or l.region_id = regionId) AND
(memberId IS NULL or l.member_id = memberId) AND
(keywords IS NULL or MATCH(l.title,l.description,r.title,c.title) AGAINST(keywords) AND
(filterDistance IS NULL OR distance = filterDistance)
IF sortField != NULL THEN
ORDER BY sortField sortOrder
ELSE
ORDER BY l.listing_id DESC
IF listingId != NULL THEN
LIMIT 1;
ELSE
LIMIT (IF page > 1 THEN ((page - 1) * perPage) ELSE 0),perPage
END IF;
END //
You cannot build dynamic queries this way.
You can compose the query as a string in a variable then use the string to prepare a statement and execute it:
# Put the common part of the query in a string. Take care to not include
# the variable names but use CONCAT() to join their *values* into the SQL syntax.
# Or, if possible, replace them with question marks (?) and pass
# them to EXECUTE as parameter values (see below or read the documentation)
SET #sql = 'SELECT l.listing_id AS id, ... OR distance = filterDistance)';
# Add the ORDER BY clause
IF sortField IS NOT NULL THEN
SET #sql = CONCAT(#sql, ' ORDER BY ', sortField, ' ', sortOrder);
ELSE
SET #sql = CONCAT(#sql, ' ORDER BY l.listing_id DESC');
END IF;
# Add the LIMIT clause; it uses parameters
SET #sql = CONCAT(#sql, ' LIMIT ?, ?');
# Compute the values of parameters to use in the LIMIT clause
IF listingId IS NOT NULL THEN
SET #start = 1;
SET #limit = 1;
ELSE
# Make sure #start is not negative
SET #start = MAX(0, (page - 1) * perPage);
SET #limit = perPage;
END IF;
# Use #sql to prepare a statement
PREPARE stmt1 FROM #sql;
# Run the prepared statement with parameters
EXECUTE stmt1 USING #start, #limit;
# Can run the prepared statement again, with different parameters if needed
# ...
# Remove the prepared statement when it is not needed any more
DEALLOCATE PREPARE stmt1;
I have the following SQL script. As you can see I manually set the #listingid value to 30653.
But this script should be executed for all records in the [listings] table where #listingid is assigned the value of the [listings].id column.
DECLARE #profname nvarchar(150)
DECLARE #furl nvarchar(250)
DECLARE #city nvarchar(250)
DECLARE #listingid int
set #listingid=30653
--select the top 1 professionname
SELECT TOP 1 #profname=REPLACE(LOWER(pn.title),' ','-'),#furl=l.friendlyurl,#city=REPLACE(REPLACE(LOWER(l.city),'''',''),' ','-') FROM healthprof_professionnames hpn
INNER JOIN professionname pn ON pn.id=hpn.professionnameid
INNER JOIN listings l on l.id=hpn.healthprofid
WHERE l.id=#listingid ORDER BY pn.title
--check if current friendlyurl already contains profession
IF NOT CHARINDEX(#profname,#furl)>0
SET #furl = #furl + '-' + #profname
IF NOT CHARINDEX(#city,#furl)>0
SET #furl = #furl + '-' + #city
SET #furl = #furl + '-3'
UPDATE listings set friendlyurl=#furl WHERE id=#listingid
You can use a cursor to loop over every row in a result set:
declare cur cursor for
select distinct id from listings
declare #listingid int
open cur
fetch next from cur into #listingid
while ##FETCH_STATUS = 0
BEGIN
-- your code from above goes here
fetch next from cur into #listingid
END
That being said, I agree with Tim's comment above. Rewrite it to work in one set-based operation if at all possible. I think this will work, but I haven't tested it:
;WITH vars AS (
SELECT id, profname, furl, city
FROM (
SELECT l.id,
REPLACE(LOWER(pn.title),' ','-') as profname,
l.friendlyurl as furl,
REPLACE(REPLACE(LOWER(l.city),'''',''),' ','-') as city,
ROW_NUMBER() OVER (PARTITION BY l.id ORDER BY pn.title) as rnk
FROM healthprof_professionnames hpn
INNER JOIN professionname pn ON pn.id=hpn.professionnameid
INNER JOIN listings l on l.id=hpn.healthprofid
) A
WHERE A.rnk = 1
),
vars2 AS (
SELECT id,
CASE WHEN NOT CHARINDEX(profname, furl) > 0
THEN furl + '-' + profname ELSE furl END as furl,
city
FROM vars
),
vars3 as (
SELECT id,
CASE WHEN NOT CHARINDEX(city, furl) > 0
THEN furl + '-' + city ELSE furl END as furl
FROM vars2
)
UPDATE listings SET friendlyurl = vars3.furl + '-3'
FROM listings INNER JOIN vars3 on vars3.id = listings.id