Can you suggest mysql function like this? - mysql

I'm sorry if this question is stupid. What I want to do:-
<---'type' is a parameter of my procedure--->
SELECT * FROM `table1` WHERE
CASE type
WHEN 'some' THEN `column1`='column1string'
WHEN 'somestr' THEN `column2` = 'column2string' AND `column1` = 'column1string'
WHEN 'somestring' THEN `column3` = 'column3string'
END IF;
But I want to write more sql queries when using case statement:-
CASE type
WHEN 'some' THEN SELECT * FROM `table1` WHERE `coumn1`='column1string';
WHEN 'somestr' THEN SELECT * FROM `table1` WHERE `coumn2`='column2string' AND `column1` = 'column1string';
WHEN 'somestring' THEN SELECT * FROM `table1` WHERE `coumn2`='column2string';
END CASE;
How can I do this without writing the same query more times. because I have 40 strings like this for comparing.

I think you can just use boolean logic:
SELECT t.*
FROM `table1` t
WHERE (type = 'some' AND `column1` = 'column1string') OR
(type = 'somestr' AND `coumn2` = 'column2string') OR
(type = 'somestring' AND `coumn2` = 'column2string');

Related

MySQL issue : adding the result of a query to a column in the same table

SELECT CONCAT(
from_unixtime(lastSaleTime/1000, '%Y-%d-%m %h:%i:%s.'),
CAST(EXTRACT(MICROSECOND FROM from_unixtime(lastSaleTime/1000))/1000
AS SIGNED)
) FROM IEX_Tick;
This code returns a column of values, and I want to add all that data to a new column that I created. This was suggested last time:
UPDATE IEX_Tick SET SomeColumn = (
SELECT CONCAT(
from_unixtime(lastSaleTime/1000, '%Y-%d-%m %h:%i:%s.'),
CAST(EXTRACT(MICROSECOND FROM from_unixtime(lastSaleTime/1000))/1000 AS SIGNED)
) FROM IEX_Tick;
)
However I get the error "You can't specify target table 'IEX_Tick' for update in FROM clause. I looked that up and we have tried some of the workarounds, for example:
UPDATE IEX_Tick SET SomeColumn = (
SELECT CONCAT(
from_unixtime(lastSaleTime/1000, '%Y-%d-%m %h:%i:%s.'),
CAST(EXTRACT(MICROSECOND FROM from_unixtime(lastSaleTime/1000))/1000 AS SIGNED)
) FROM (Select * from IEX_Tick) as RRR;
)
But it still doesn't work
Simply eschew the subquery:
UPDATE IEX_Tick
SET SomeColumn = CONCAT(from_unixtime(lastSaleTime/1000, '%Y-%d-%m %h:%i:%s.'),
CAST(EXTRACT(MICROSECOND FROM from_unixtime(lastSaleTime/1000))/1000 AS SIGNED)
);

How to get a specific column by its ordinal position in table using SQL? [duplicate]

Is there any SQL lingo to return JUST the first two columns of a table WITHOUT knowing the field names?
Something like
SELECT Column(1), Column(2) FROM Table_Name
Or do I have to go the long way around and find out the column names first? How would I do that?
You have to get the column names first. Most platforms support this:
select column_name,ordinal_position
from information_schema.columns
where table_schema = ...
and table_name = ...
and ordinal_position <= 2
There it´s
declare #select varchar(max)
set #select = 'select '
select #select=#select+COLUMN_NAME+','
from information_schema.columns
where table_name = 'TABLE' and ordinal_position <= 2
set #select=LEFT(#select,LEN(#select)-1)+' from TABLE'
exec(#select)
A dynamic query using for xml path will also do the job:
declare #sql varchar(max)
set #sql = (SELECT top 2 COLUMN_NAME + ',' from information_schema.columns where table_name = 'YOUR_TABLE_NAME_HERE' order by ordinal_position for xml path(''))
set #sql = (SELECT replace(#sql +' ',', ',''))
exec('SELECT ' + #sql + ' from YOUR_TABLE_NAME_HERE')
I wrote a stored procedure a while back to do this exact job. Even though in relational theory there is no technical column order SSMS is not completely relational. The system stores the order in which the columns were inserted and assigns an ID to them. This order is followed using the typical SELECT * statement which is why your SELECT statements appear to return the same order each time. In practice its never a good idea to SELECT * with anything as it doesn't lock the result order in terms of columns or rows. That said I think people get so stuck on 'you shouldn't do this' that they don't write scripts that actually can do it. Fact is there is predictable system behavior so why not use it if the task isn't super important.
This SPROC of course has caveats and is written in T-SQL but if your looking to just return all of the values with the same behavior of SELECT * then this should do the job pretty easy for you. Put in your table name, the amount of columns, and hit F5. It returns them in order from left to right the same as you'd be expecting. I limited it to only 5 columns but you can edit the logic if you need any more. Takes both temp and permanent tables.
EXEC OnlySomeColumns 'MyTable', 3
/*------------------------------------------------------------------------------------------------------------------
Document Title: The Unknown SELECT SPROC.sql
Created By: CR
Date: 4.28.2013
Purpose: Returns all results from temp or permanent table when not knowing the column names
SPROC Input Example: EXEC OnlySomeColumns 'MyTable', 3
--------------------------------------------------------------------------------------------------------------------*/
IF OBJECT_ID ('OnlySomeColumns', 'P') IS NOT NULL
DROP PROCEDURE OnlySomeColumns;
GO
CREATE PROCEDURE OnlySomeColumns
#TableName VARCHAR (1000),
#TotalColumns INT
AS
DECLARE #Column1 VARCHAR (1000),
#Column2 VARCHAR (1000),
#Column3 VARCHAR (1000),
#Column4 VARCHAR (1000),
#Column5 VARCHAR (1000),
#SQL VARCHAR (1000),
#TempTable VARCHAR (1000),
#PermanentTable VARCHAR (1000),
#ColumnNamesAll VARCHAR (1000)
--First determine if this is a temp table or permanent table
IF #TableName LIKE '%#%' BEGIN SET #TempTable = #TableName END --If a temporary table
IF #TableName NOT LIKE '%#%' BEGIN SET #PermanentTable = #TableName END --If a permanent column name
SET NOCOUNT ON
--Start with a few simple error checks
IF ( #TempTable = 'NULL' AND #PermanentTable = 'NULL' )
BEGIN
RAISERROR ( 'ERROR: Please select a TempTable or Permanent Table.',16,1 )
END
IF ( #TempTable <> 'NULL' AND #PermanentTable <> 'NULL' )
BEGIN
RAISERROR ( 'ERROR: Only one table can be selected at a time. Please adjust your table selection.',16,1 )
END
IF ( #TotalColumns IS NULL )
BEGIN
RAISERROR ( 'ERROR: Please select a value for #TotalColumns.',16,1 )
END
--Temp table to gather the names of the columns
IF Object_id('tempdb..#TempName') IS NOT NULL DROP TABLE #TempName
CREATE TABLE #TempName ( ID INT, Name VARCHAR (1000) )
--Select the column order from a temp table
IF #TempTable <> 'NULL'
BEGIN
--Verify the temp table exists
IF NOT EXISTS ( SELECT 1
FROM tempdb.sys.columns
WHERE object_id = object_id ('tempdb..' + #TempTable +'') )
BEGIN
RAISERROR ( 'ERROR: Your TempTable does not exist - Please select a valid TempTable.',16,1 )
RETURN
END
SET #SQL = 'INSERT INTO #TempName
SELECT column_id AS ID, Name
FROM tempdb.sys.columns
WHERE object_id = object_id (''tempdb..' + #TempTable +''')
ORDER BY column_id'
EXEC (#SQL)
END
--From a permanent table
IF #PermanentTable <> 'NULL'
BEGIN
--Verify the temp table exists
IF NOT EXISTS ( SELECT 1
FROM syscolumns
WHERE id = ( SELECT id
FROM sysobjects
WHERE Name = '' + #PermanentTable + '' ) )
BEGIN
RAISERROR ( 'ERROR: Your Table does not exist - Please select a valid Table.',16,1 )
RETURN
END
SET #SQL = 'INSERT INTO #TempName
SELECT colorder AS ID, Name
FROM syscolumns
WHERE id = ( SELECT id
FROM sysobjects
WHERE Name = ''' + #PermanentTable + ''' )
ORDER BY colorder'
EXEC (#SQL)
END
--Set the names of the columns
IF #TotalColumns >= 1 BEGIN SET #Column1 = (SELECT Name FROM #TempName WHERE ID = 1) END
IF #TotalColumns >= 2 BEGIN SET #Column2 = (SELECT Name FROM #TempName WHERE ID = 2) END
IF #TotalColumns >= 3 BEGIN SET #Column3 = (SELECT Name FROM #TempName WHERE ID = 3) END
IF #TotalColumns >= 4 BEGIN SET #Column4 = (SELECT Name FROM #TempName WHERE ID = 4) END
IF #TotalColumns >= 5 BEGIN SET #Column5 = (SELECT Name FROM #TempName WHERE ID = 5) END
--Create a select list of only the column names you want
IF Object_id('tempdb..#FinalNames') IS NOT NULL DROP TABLE #FinalNames
CREATE TABLE #FinalNames ( ID INT, Name VARCHAR (1000) )
INSERT #FinalNames
SELECT '1' AS ID, #Column1 AS Name UNION ALL
SELECT '2' AS ID, #Column2 AS Name UNION ALL
SELECT '3' AS ID, #Column3 AS Name UNION ALL
SELECT '4' AS ID, #Column4 AS Name UNION ALL
SELECT '5' AS ID, #Column5 AS Name
--Comma Delimite the names to insert into a select statement. Bracket the names in case there are spaces
SELECT #ColumnNamesAll = COALESCE(#ColumnNamesAll + '], [' ,'[') + Name
FROM #FinalNames
WHERE Name IS NOT NULL
ORDER BY ID
--Add an extra bracket at the end to complete the string
SELECT #ColumnNamesAll = #ColumnNamesAll + ']'
--Tell the user if they selected to many columns
IF ( #TotalColumns > 5 AND EXISTS (SELECT 1 FROM #FinalNames WHERE Name IS NOT NULL) )
BEGIN
SELECT 'This script has been designed for up to 5 columns' AS ERROR
UNION ALL
SELECT 'Only the first 5 columns have been selected' AS ERROR
END
IF Object_id('tempdb..#FinalNames') IS NOT NULL DROP TABLE ##OutputTable
--Select results using only the Columns you wanted
IF #TempTable <> 'NULL'
BEGIN
SET #SQL = 'SELECT ' + #ColumnNamesAll + '
INTO ##OutputTable
FROM ' + #TempTable + '
ORDER BY 1'
EXEC (#SQL)
END
IF #PermanentTable <> 'NULL'
BEGIN
SET #SQL = 'SELECT ' + #ColumnNamesAll + '
INTO ##OutputTable
FROM ' + #PermanentTable + '
ORDER BY 1'
EXEC (#SQL)
END
SELECT *
FROM ##OutputTable
SET NOCOUNT OFF
SQL doesn't understand the order of columns. You need to know the column names to get them.
You can look into querying the information_schema to get the column names. For example:
SELECT column_name
FROM INFORMATION_SCHEMA.COLUMNS
WHERE table_name = 'tbl_name'
ORDER BY ordinal_position
LIMIT 2;
You can query the sysobject of the table to find out the first two column then dynamically generate the SQL statement you need.
If you want a permant object that you can query over and over again make a view for each table that only returns the first 2 columns. You can name the columns Column1 and Column2 or use the existing names.
If you want to return the first two columns from any table without any preprocessing steps create a stored procedure that queries the system information and executes a dynamic query that return the first two columns from the table.
Or do I have to go the long way around and find out the column names first? How would I do that?
It's pretty easy to do manually.
Just run this first
select * from tbl where 1=0
This statement works on all major DBMS without needing any system catalogs.
That gives you all the column names, then all you need to do is type the first two
select colname1, colnum2 from tbl

MySQL IF THEN ELSE

I'm trying to make a IF EXISTS UPDATE ELSE INSERT statement but I get errors around the UPDATE line. I could do this in two separate queries but I'm not sure what would be better.
I've tried to follow this guide but didn't manage to make my query work. https://blog.udemy.com/sql-if-then/
IF EXISTS
(
SELECT 1
FROM `table`
WHERE
`column` = 'value'
)
THEN
(
UPDATE `table` SET
`date` = NOW()
WHERE
`column` = 'value'
)
ELSE
(
INSERT INTO `table` SET
`date` = NOW(),
`column` = 'value'
)
END IF
END
Would this help?
INSERT ... ON DUPLICATE KEY UPDATE
https://dev.mysql.com/doc/refman/5.7/en/insert-on-duplicate.html
In your case "column" would be a unique key

How to pass multiple parameters into a mysql stored procedure

I have a stored procedure that I am working on that is returning an invalid return when I try to pass parameters to it compared to when I run it with hard-coded values.
Procedure with hard coded values:
BEGIN
SELECT COUNT(DISTINCT ItemID)
FROM (
SELECT *
FROM sandbox_inventoryitempurchase
WHERE OrgID = '2781823'
AND PurchaseMonth>'2015-03-01'
) as DistinctCount;
END
When run, this returns: 16 which is correct.
Procedure with two input parameters:
BEGIN
SELECT COUNT(DISTINCT ItemID)
FROM (
SELECT *
FROM sandbox_inventoryitempurchase
WHERE OrgID = orgid
AND PurchaseMonth>sincedate
) as DistinctCount;
END
The input parameters are defined as:
IN userid integer,IN orgid integer,IN sincedate date
When run, this returns: 334 which is not correct.
I am new to stored procedures and would appreciate any assistance offered regarding what I am doing wrong and what I need to do to resolve?
Thanks...
add "#" before your parameters:
BEGIN
SELECT COUNT(DISTINCT ItemID)
FROM (
SELECT *
FROM sandbox_inventoryitempurchase
WHERE OrgID = #orgid
AND PurchaseMonth>#sincedate
) as DistinctCount;
END
a fast turtorial will be: Write-a-Stored-Procedure-in-SQL
(see how to use parameters at the end of this page...)
Try using input parameters that are not the same name as your columns.
Change:
BEGIN
SELECT COUNT(DISTINCT ItemID)
FROM (
SELECT *
FROM sandbox_inventoryitempurchase
WHERE OrgID = orgid
AND PurchaseMonth>sincedate
) as DistinctCount;
END
To:
BEGIN
SELECT COUNT(DISTINCT ItemID)
FROM (
SELECT *
FROM sandbox_inventoryitempurchase
WHERE OrgID = p_orgid
AND PurchaseMonth > p_sincedate
) as DistinctCount;
END
And pass IN p_orgid integer,IN p_sincedate date
The parser may be seeing WHERE OrgID = orgid and that evaluates to true for every record since it evaluates as an identity (comparing against itself).
Param Name and field name must be different!
BEGIN
SELECT COUNT(DISTINCT ItemID)
FROM (
SELECT *
FROM sandbox_inventoryitempurchase
WHERE OrgID = p_orgid
AND PurchaseMonth > p_sincedate
) as DistinctCount;
END

Chaining SQL queries

Right now I'm running
SELECT formula('FOO') FROM table1
WHERE table1.foo = 'FOO' && table1.bar = 'BAR';
but I would like to run this not on the constant FOO but on each value from the query
SELECT foos FROM table2
WHERE table2.bar = 'BAR';
How can I do this?
Edit: Important change: added FOO to the arguments of function.
Illustration:
SELECT foo FROM table1 WHERE foo = 'FOO' && table1.bar = 'BAR';
gives a column with FOOa, FOOb, FOOc.
SELECT formula('FOO') FROM table1
WHERE table1.foo = 'FOO' && table1.bar = 'BAR';
gives a single entry, say sum(FOO) (actually much more complicated, but it uses aggregates at some point to combine the results).
I want some query which gives a column with sum(FOO1), sum(FOO2), ... where each FOOn is computed in like manner to FOO. But I'd like to do this with one query rather than n queries (because n may be large and in any case the particular values of FOOn vary from case to case).
Try this one:
SELECT formula FROM table1
WHERE table1.foo IN(SELECT foos FROM table2
WHERE table2.bar = 'BAR';
) AND table1.bar = 'BAR';
SELECT formula FROM table1 WHERE bar = 'BAR' AND foo IN (SELECT foos FROM table2 WHERE bar = 'BAR');
EDIT:
This isn't tested, but perhaps this will work?
SELECT formula(q1.foo) FROM table1 INNER JOIN (SELECT foo, bar FROM table2) q1 ON table1.foo = q1.foo WHERE table1.bar = 'BAR';
You will have to use dynamic SQL statements.
The way this works is that you just string the SQL statement together using parameters.
You will need to be careful though not to allow users to feed that data, because escaping cannot protect you against SQL-injection. You will need to check every column name against a whitelist.
Here's example code in a stored procedure.
The way this works, is that you have a (temporary) table with column names and the stored procedure builds this into a query:
dynamic /*holds variable parts of an SQL statement
-----------
id integer PK
column_name varchar(255)
operation ENUM('what','from','where','group by','having','order by','limit')
function_name varchar(255) /*function desc with a '#' placeholder where */
/* the column-name goes */
whitelist /*holds all allowed column names*/
-----------
id integer PK
allowed varchar(255) /*allowed column of table name*/
item ENUM('column','table')
Dynamic SQL stored procedure. Expects two tables: dynamic and whitelist to be prefilled.
DELIMITER $$
CREATE PROCEDURE dynamic_example;
BEGIN
DECLARE vwhat VARCHAR(65000);
DECLARE vfrom VARCHAR(65000);
DECLARE vwhere VARCHAR(65000);
DECLARE vQuery VARCHAR(65000);
SELECT group_concat(REPLACE(function_name,'#',column_name)) INTO vwhat
FROM dynamic
INNER JOIN whitelist wl ON (wl.allowed LIKE column_name
AND wl.item = 'column')
WHERE operation = 'what' AND
SELECT group_concat(REPLACE(function_name,'#',column_name)) INTO vfrom
FROM dynamic
INNER JOIN whitelist wl ON (wl.allowed LIKE column_name
AND wl.item = 'table')
WHERE operation = 'from';
SELECT group_concat(REPLACE(function_name,'#',column_name)) INTO vwhere
FROM dynamic
INNER JOIN whitelist wl ON (wl.allowed LIKE column_name
AND wl.item = 'column')
WHERE operation = 'where';
IF vwhat IS NULL THEN SET vwhat = ' * ';
IF vwhere IS NOT NULL THEN SET vwhere = CONCAT(' WHERE ',vwhere); END IF;
SET vQuery = CONCAT(' SELECT ',vwhat,' FROM ',vfrom,IFNULL(vwhere,''));
PREPARE dSQL FROM vQuery;
EXECUTE dSQL;
DEALLOCATE PREPARE dSQL;
END $$
DELIMITER ;
Try:
SELECT formula FROM table1, table2
WHERE table1.foo = table2.foo AND table1.bar = table2.bar;