T-SQL view where statement order - tsql

I have the following problem:
I have an SQL table which contains texts and numbers in one column. I created two views to handle the texts and the numbers.
If I select the views in whole, they work as expected, but if I add a where statement to the select statement, I get the following error:
Conversion failed when converting the varchar value 'Thomas' to data type int.
Can I somehow tell the server to apply for the inner view's where statement before the outer select's one?
Please use the following SQL code for reproducing the error:
create schema tst
go
create table tst.tbl(strValue varchar(10))
insert tst.tbl(strValue)
values ('Thomas'), ('1991'), ('Reto'), ('21'), ('Strub')
go
create view tst.tblStr as
select strValue
from tst.tbl
where isnumeric(strValue)=0
go
create view tst.tblInt as
select cast(strValue as int) intValue
from tst.tbl
where isnumeric(strValue)=1
go
select * from tst.tblStr order by strValue --ok
select * from tst.tblInt order by intValue --ok
go
select * from tst.tblInt where intValue<100 --not ok
go
select * from tst.tbl where isnumeric(strValue)=1 and cast(strValue as int) < 100 --ok
go
drop view tst.tblInt
drop view tst.tblStr
drop table tst.tbl
drop schema tst

Use a "case when" for view tst.tblInt.
create view tst.tblInt as
select
case when isnumeric(strValue)=1
then cast(strValue as int)
else 0
end intValue
from tst.tbl
where isnumeric(strValue)=1

I belive answer you already posted, just modfied a single line please check
CREATE SCHEMA TST
GO
CREATE TABLE TST.TBL(STRVALUE VARCHAR(10))
INSERT TST.TBL(STRVALUE)
VALUES ('THOMAS'), ('1991'), ('RETO'), ('21'),('24'),('212'), ('STRUB')
GO
CREATE VIEW TST.TBLSTR AS
SELECT STRVALUE
FROM TST.TBL
WHERE ISNUMERIC(STRVALUE)=0
GO
CREATE VIEW TST.TBLINT AS
SELECT CAST(STRVALUE AS INT) INTVALUE
FROM TST.TBL
WHERE ISNUMERIC(STRVALUE)=1
GO
SELECT * FROM TST.TBLSTR ORDER BY STRVALUE --OK
SELECT * FROM TST.TBLINT ORDER BY INTVALUE --OK
GO
**SELECT * FROM TST.TBLINT WHERE ISNUMERIC(INTVALUE)<100 --NOW OK ;)**
GO
SELECT * FROM TST.TBL WHERE ISNUMERIC(STRVALUE)=1 AND CAST(STRVALUE AS INT) < 100 --OK
GO
DROP VIEW TST.TBLINT
DROP VIEW TST.TBLSTR
DROP TABLE TST.TBL
DROP SCHEMA TST

Related

How to access individual elements of user defined data types?

This is a Postgres SQL question.
I am having a user defined data type as follows.
create type my_type as (name varchar(100), credit_points double precision)
I am having a table which uses the above type as column's datatype as below.
create table tab1 (
id serial,
name_credit my_type
)
I could insert values into this table using below insert statement.
insert into tab1 (name_credit) values(('santhosh', 101.75)::my_type)
Now, I want to access the table like below.
select * from tab1 where name_credit[2] between 100.0 and 110.0
or
select * from tab1 where name_credit.credit_points between 100.0 and 110.0
But neither of it is working for me. Any ideas please?
Put the column name in ().
SELECT *
FROM tab1
WHERE (name_credit).credit_points BETWEEN 100.0
AND 110.0;
See "8.16.3. Accessing Composite Types" for more details.

Invalid column name of temp table

I want to create a procedure in which I insert data into several tables. I need to get the inserted ID's so I create temp table in which I catch them. The problem is that I receive an error "Invalid column name 'app_guid'" and "Invalid column name 'app_nazwa_pliku'" but I create temp tables with such columns. Do you happen to know what's wrong with my code?
create procedure p_paseczek_przenies
as
declare #new_nr_sprawy varchar(50)
if object_id('tempdb..##paseczki') is not null drop table ##paseczki
select
top 1 with ties
s.sp_numer as SprawaGlowna_sp_numer,
s.sp_id as SprawaGlowna_sp_id
,Paseczek.max_ak_id as Paseczek_max_ak_id
,apisp_data_przyjscia
,app_guid
,app_nazwa_pliku
into ##paseczki
from sprawa as s
join akcja as a on a.ak_sp_id=s.sp_id and ak_akt_id=111
join sprawa_powiazania as sp on s.sp_id=sp.sp_id and rodzaj_powiazania='SPRAWY POLUBOWNE'
join (select max(ak_id) max_ak_id,ak_sp_id from akcja
where ak_akt_id=1089
group by ak_sp_id) as Paseczek on Paseczek.ak_sp_id=sp.sp_id_powiazana
join akcja_pismo on apis_ak_id=max_ak_id
join akcja_pismo_przychodzace on apis_apisp_id=apisp_id
join akcja_pismo_plik on app_apis_id=apis_id
where s.sp_numer=#new_nr_sprawy
order by ROW_NUMBER() over (partition by s.sp_id order by paseczek.max_ak_id desc)
if exists (select * from ##paseczki)
begin
if object_id('tempdb..##akcja') is not null drop table ##akcja
create table ##akcja (
ak_id int
,apisp_data_przyjscia datetime
,app_guid varchar(max)
,app_nazwa_pliku varchar(max)
)
merge akcja as target using (
select * from ##paseczki) as source on 1=0
when not matched then insert
(ak_akt_id, ak_sp_id, ak_kolejnosc, ak_interwal, ak_zakonczono, ak_pr_id, ak_publiczna)
values (1089,SprawaGlowna_sp_id,1,1,getdate(),5,1)
output inserted.ak_id,source.apisp_data_przyjscia,source.app_guid,source.app_nazwa_pliku
into ##akcja;
insert into rezultat
(re_ak_id, re_ret_id, re_data_planowana, re_us_id_planujacy, re_data_wykonania, re_us_id_wykonujacy, re_konczy)
select ak_id,309,getdate(),5,getdate(),5,1 from ##akcja
if object_id('tempdb..##akcja_pismo_przychodzace') is not null drop table ##akcja_pismo_przychodzace
create table ##akcja_pismo_przychodzace (
apisp_id int
,ak_id int
,app_guid varchar(max)
,app_nazwa_pliku varchar(max)
)
merge akcja_pismo_przychodzace as target using (
select * from ##akcja) as source on 1=0
when not matched then insert
(apisp_data_przyjscia)
values (apisp_data_przyjscia)
output inserted.apisp_id,source.ak_id,source.app_guid,source.app_nazwa_pliku
into ##akcja_pismo_przychodzace;
if object_id('tempdb..##akcja_pismo') is not null drop table ##akcja_pismo
create table ##akcja_pismo (
apis_id int
,app_guid varchar(max)
,app_nazwa_pliku varchar(max)
)
merge akcja_pismo as target using (
select * from ##akcja_pismo_przychodzace) as source on 1=0
when not matched then insert
(apis_ak_id, apis_apisp_id, apis_data_stworzenia,[apis_us_id_tworzacy])
values (ak_id,apisp_id,getdate(),5)
output inserted.apis_id,source.app_guid,source.app_nazwa_pliku
into ##akcja_pismo;
alter table [dm_data_bps].[dbo].[akcja_pismo_plik] disable trigger [tr_akcja_pismo_plik_ins]
insert into akcja_pismo_plik
([app_guid],[app_apis_id],[app_nazwa_pliku])
select [app_guid],[apis_id],[app_nazwa_pliku] from ##akcja_pismo
alter table [dm_data_bps].[dbo].[akcja_pismo_plik] enable trigger [tr_akcja_pismo_plik_ins]
end
SQL Server compiles the procedure at creation and when it is first executed, verifying the entire procedure based on the context at that time.
For example, try the following query:
CREATE PROCEDURE P
AS
IF OBJECT_ID('tempdb..#T') IS NOT NULL DROP TABLE #T
SELECT 1 Y INTO #T
SELECT Y FROM #T
GO
CREATE TABLE #T (X INT)
GO
EXEC P
You will get an error ("Invalid column name 'Y'."), because when the procedure is compiled the table #T has only the column X.
To avoid this problem, you should make sure that the table #T either does not exist or has the right columns, before the procedure is executed.
One way would be to have another stored procedure (a wrapper):
CREATE PROCEDURE P1
AS
SELECT 1 Y INTO #T
SELECT Y FROM #T
GO
CREATE PROCEDURE P2
AS
IF OBJECT_ID('tempdb..#T') IS NOT NULL DROP TABLE #T
EXEC P1
GO
CREATE TABLE #T (X INT)
GO
EXEC P2
GO
DROP PROCEDURE P1, P2
--DROP TABLE #T
Another way would be to use dynamic SQL, because that code is compiled separately, as if it would be another stored procedure.
A better way would be to make sure that temp tables are uniquely named in each stored procedure, unless sharing data between them is desired. For the later case, you can read http://www.sommarskog.se/share_data.html#temptables for more insights.
This error is also encountered when a stored procedure creates a #temp table and then fires a trigger which creates a #temp table with the same name. The SP #temp table is referenced by the trigger when the column names are explicit, (like SELECT id FROM #temp;), but the local trigger #temp table is referenced when SELECT * FROM #temp; is used.
Microsoft, if you are listening, could you kindly attend to it and retrofit existing supported versions with a maintenance update?

IF Exists doesn't seem to work for a Table Drop if already exists

Was getting this error each and every time tried to execute a DROP Table if exists
Step 1: Created a Table
CREATE TABLE Work_Tables.dbo.Drop_Table_Test (RowID INT IDENTITY(1,1), Data VARCHAR(50))
INSERT INTO Work_Tables.dbo.Drop_Table_Test
SELECT 'Test' UNION
SELECT 'Test1' UNION
SELECT 'Test2' UNION
SELECT 'Test3'
Step 2: Wrote a IF Exists block to check if the Table exists.
IF EXISTS (SELECT 1 FROM Work_Tables.dbo.SysObjects WHERE NAME LIKE 'Drop_Table_Test' AND XType = 'U')
BEGIN
PRINT 'IN'
DROP TABLE Work_Tables.dbo.Drop_Table_Test
END
CREATE TABLE Work_Tables.dbo.Drop_Table_Test (RowID INT IDENTITY(1,1), Data VARCHAR(50), NAME VARCHAR(20), PreCheck INT)
INSERT INTO Work_Tables.dbo.Drop_Table_Test (Data, Name, PreCheck)
SELECT 'Test','SRK',1 UNION
SELECT 'Test1','Daya',2 UNION
SELECT 'Test2','Dinesh',3 UNION
SELECT 'Test3','Suresh',4
On running the Step 2 Code its obvious the Table has to be Dropped and recreated with the same name but it didn't even enter the Begin End block.
I feel that its because have added few more columns in the second try, but still not clear why it should have problems as we are to DROP the table.
You can not drop and create the same table in the same batch in SQL Server.
Break your code up into separate batches so the table can be dropped before you try and recreate it. Add GO after END in your BEGIN / END statement.
IF EXISTS (SELECT 1 FROM Work_Tables.dbo.SysObjects WHERE NAME LIKE 'Drop_Table_Test' AND XType = 'U')
BEGIN
PRINT 'IN'
DROP TABLE Work_Tables.dbo.Drop_Table_Test
END
GO --Add this...
....
Straight from Microsoft's Documentation:
DROP TABLE and CREATE TABLE should not be executed on the same table in the same batch. Otherwise an unexpected error may occur.
You can try to use this syntax:
IF OBJECT_ID('dbo.Drop_Table_Test', 'U') IS NOT NULL
DROP TABLE dbo.Drop_Table_Test;
IF EXISTS will drop the table only when your table Drop_Table_Test does not contain any row. In case if it contains the data then it will not drop the table.

how to change a table column datatype in a view in postgresql

))Hi all, I have an 'Interval' datatype column in mytable that I would like to change to 'character varying' datatype in mytableview.
I know I can change it using...
to_char(interval, 'yy-mm-dd HH24:MI:SS.MS');
But I would like to leave that column datatype as 'interval' in mytable, and make a view of that table changing the 'interval' column to 'character varying' datatype in mytableview.
was so easy...
CREATE TABLE mytable (length INTERVAL);
INSERT INTO mytable (length) VALUES (INTERVAL '1 minute');
CREATE VIEW myview AS
SELECT to_char(length, 'yy-mm-dd HH24:MI:SS.MS') AS length
FROM mytable;
Is that possible? Thanks Advanced.
You can specify your view just like you'd specify any other query without needing to change the underlying table types. Here's a Fiddle with your example.
CREATE TABLE mytable (length INTERVAL);
INSERT INTO mytable (length) VALUES (INTERVAL '1 minute');
CREATE VIEW myview AS
SELECT to_char(length, 'yy-mm-dd HH24:MI:SS.MS') AS length
FROM mytable;
SELECT * FROM mytable;
-- 0 years 0 mons 0 days 0 hours 1 mins 0.00 secs
SELECT * FROM myview;
-- 00-00-00 00:01:00.000

SQL Union exclude row if value already exists in first table

I have two tables which i wish to combine. However, there is a field in both tables that should have the same value in the second table the second tables record should be excluded.
These are a MSSQL 2012 tables.
The only way i can think of is something nasty like this.
Select A, B
from Tab1
Union
Select C, D
from Tab2
where Tab2.c not in (Select A from Tab1)
It looks relatively clean in my example but the selects for Tab1 and tab2 have long and complex where clauses and i would need to duplicated that in the "not in" select statement.
I've seen other solutions but not in MSSQL. Any one out there have a better example ?
Thanks
well in t-sql i use this kind of code
USE tempdb
GO
CREATE TABLE StudentDetails
(
StudentID INTEGER PRIMARY KEY,
StudentName VARCHAR(15)
)
GO
INSERT INTO StudentDetails
VALUES(1,'SMITH')
INSERT INTO StudentDetails
VALUES(2,'ALLEN')
INSERT INTO StudentDetails
VALUES(3,'JONES')
INSERT INTO StudentDetails
VALUES(4,'MARTIN')
INSERT INTO StudentDetails
VALUES(5,'JAMES')
GO
CREATE TABLE StudentTotalMarks
(
StudentID INTEGER REFERENCES StudentDetails,
StudentMarks INTEGER
)
GO
INSERT INTO StudentTotalMarks
VALUES(1,230)
INSERT INTO StudentTotalMarks
VALUES(2,255)
INSERT INTO StudentTotalMarks
VALUES(3,200)
GO
-- Select from Table
SELECT *
FROM StudentDetails
GO
SELECT *
FROM StudentTotalMarks
GO
-- Merge Statement
MERGE StudentTotalMarks AS stm
USING (SELECT StudentID,StudentName FROM StudentDetails) AS sd
ON stm.StudentID = sd.StudentID
WHEN MATCHED AND stm.StudentMarks > 250 THEN DELETE
WHEN MATCHED THEN UPDATE SET stm.StudentMarks = stm.StudentMarks + 25
WHEN NOT MATCHED THEN
INSERT(StudentID,StudentMarks)
VALUES(sd.StudentID,25);
GO
-- Select from Table
SELECT *
FROM StudentDetails
GO
SELECT *
FROM StudentTotalMarks
GO
-- Clean up
DROP TABLE StudentDetails
GO
DROP TABLE StudentTotalMarks
GO
The Merge Join performs very well and the following result is obtained.
http://www.pinaldave.com/bimg/MergeStatement.gif
Hope this helps