"Invalid Column Name" even though the column is created? - sql

I have created a table :
create table Praktikant(
Pr_id char not null Primary key,
Name varchar(100) not null,
Mbiemri varchar(100) not null,
Gender char(1) not null,
Degree varchar(100) not null,
age int,
check (age >18),
foreign key (Pr_id) references Doctor(Dr_id) on update cascade
)
Inserts:
insert into Praktikant values ('1', 'Kastriot', 'Tusha', 'M', 'Student', 19);
insert into Praktikant values ('2', 'Trim', 'Dalipi', 'M', 'Student', 23);
insert into Praktikant values ('3', 'Elira', 'Rrmoku', 'F', 'Studente', 24);
insert into Praktikant values ('4', 'Qendresa', 'Krasniqi', 'F', 'Studente',20);
Query:
select age
from Praktikant
where age > 23
I don't understand why I get this message:
Msg 207, Level 16, State 1, Line 1
Invalid column name 'age'.

Use this query to get table info:
SELECT * FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME = 'Praktikant'
then find your table schema because i suspect that you have two tables with the same name in another schema.
after find schema use this query for select info:
select age
from [schema_name].[Praktikant]
where age > 23
You can use this query to get table columns list to check:
SELECT * FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'Praktikant'

Related

CREATE FUNCTION for attribute to at most 3 people?

I am currently doing a hotel booking application on SQL Server 2018, and am trying to write a constraint for the RoomNo attribute of my SQL Server table. Essentially, I want each RoomNo to only be able to have at most 3 person, but ran into an error when trying to do the CREATE FUNCTION.
This are my current code:
CREATE TABLE Passenger
(
ID smallint ,
Name varchar (50) NOT NULL,
Email varchar (319) NULL,
DOB smalldatetime NOT NULL,
Gender char (1) NOT NULL CHECK (Gender IN ('M', 'F')),
RoomNo tinyint NOT NULL,
CONSTRAINT PK_Passenger PRIMARY KEY NONCLUSTERED (ID),
CONSTRAINT CHK_Passenger_Gender CHECK (Gender IN ('M', 'F'))
)
CREATE FUNCTION CalculateRoomNo
(
#value tinyint
)
RETURNS bit
AS
BEGIN
IF (SELECT COUNT(RoomNo) FROM Passenger GROUP BY RoomNo) <= 3
RETURN 0
RETURN 1
END
GO
ALTER TABLE Passenger
ADD CONSTRAINT CHK_RoomNoPax CHECK (dbo.CalculateRoomNo(RoomNo) = 0)
GO
When I add a passenger into the table, if it is formatted like this:
INSERT INTO Passenger
VALUES (1, 'Rob', 'Rob#gmail.com', '2017-10-04', 'M', 12)
INSERT INTO Passenger
VALUES (2, 'Darren', 'Darren#yahoo,com', '1976-12-21', 'F', 12)
INSERT INTO Passenger
VALUES (3, 'Peggy', '', '2006-03-15', 'F', 12)
INSERT INTO Passenger
VALUES (4, 'Carlos', '', '1981-04-06', 'F', 12)
It will stop at
INSERT INTO Passenger VALUES (3, 'Peggy', '', '2006-03-15', 'F', 12)
since RoomNo '12' has reached its maximum capacity.
But, if I added the values like such where the room numbers are different from each other:
INSERT INTO Passenger
VALUES (1, 'Rob', 'Rob#gmail.com', '2017-10-04', 'M', 69)
INSERT INTO Passenger
VALUES (2, 'Darren', 'Darren#yahoo,com', '1976-12-21', 'F', 74)
INSERT INTO Passenger
VALUES (3, 'Peggy', '', '2006-03-15', 'F', 45)
INSERT INTO Passenger
VALUES (4, 'Carlos', '', '1981-04-06', 'F', 72)
INSERT INTO Passenger
VALUES (5, 'John', 'johnny#hotmail.com', '1988-05-06', 'M', 69)
It will return an error:
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
Is there any way I can properly run this SQL?
The query with the GROUP BY can return more than 1 record if there's more than 1 RoomNo.
If you include a WHERE clause for the RoomNo then it can only be 1 COUNT
CREATE FUNCTION CalculateRoomNo
(
#RoomNo tinyint
)
RETURNS bit
AS
BEGIN
IF (SELECT COUNT(*) FROM Passenger WHERE RoomNo = #RoomNo) <= 3
RETURN 0
RETURN 1
END
Demo on db<>fiddle here
As mentioned by #LukStorms, your query has no filter on RoomNo, therefore it can return multiple rows. A scalar subquery must return a maximum of one row.
But the most correct way to achieve what you are trying to do, is not to use this function at all. Instead you can add another column, and create a unique constraint across that and the RoomNo
ALTER TABLE Passenger
ADD RoomNoPax tinyint NOT NULL
CONSTRAINT CHK_RoomNoPax CHECK (RoomNoPax >= 1 AND RoomNoPax <= 3);
ALTER TABLE Passenger
ADD CONSTRAINT UQ_RoomNo_RoomNoPax UNIQUE (RoomNo, RoomNoPax);
db<>fiddle
You now have an extra column which must have the value 1, 2 or 3. And there is a unique constraint over every pair of that value and the RoomNo, so you cannot now put more than 3 Passenger in each RoomNo.
You need to change the logic in the function.
You should be checking for the number of records for any given roomno, not the number of roomno in the entire table.
the subquery should return only one scalar value because you are performing a logical operation.
i.e.
if exists (select 1 from Passenger group by roomno having count(1) <= 3)
begin
return 1
end
else
begin
return 0
end
In the above query, we are checking for the number of persons assigned to each room number and if there is an existence of such case then it will return 1. In this case, it will not return more than one record.
Please modify the return value as per your requirement.
Please upvote if you find this answer useful

Get individual values from comma seperated values in the table [duplicate]

This question already has answers here:
Replace comma separated master data with description in a column
(3 answers)
Closed 4 years ago.
I have a table with reference values and another table as selected reference values. In this table the selected reference value are comma separated. How can I get individual values from comma separated values?
CREATE TABLE [DBO].[TBL_REFERENCE]
(
/* REFERENCE TABLE */
REF_ID BIGINT IDENTITY(1, 1) NOT NULL
,REF_NUMBER INT NOT NULL
,REF_NAME NVARCHAR(20)
,REF_VALUE NVARCHAR(25)
,CONSTRAINT PK_REFERENCE PRIMARY KEY (REF_ID)
)
INSERT INTO TBL_REFERENCE (ref_number, ref_name, ref_value)
VALUES (1, 'communication', 'mobile'),
(1, 'communication', 'laptop'),
(1, 'communication', 'PDA'),
(1, 'communication', 'tabs'),
(1, 'communication', 'iphone'),
(1, 'communication', 'smart phone'),
(1, 'communication', 'others');
Another table
CREATE TABLE [DBO].[TBL_FACILITY]
(
/* FACILITY TABLE */
FACILITY_ID BIGINT IDENTITY(1, 1) NOT NULL
,FAMILY_HEAD_ID BIGINT NOT NULL
,FACILITY_SELECTED INT --- REF_NAME
,FACILITY_USED NVARCHAR(25) --- ref_value
,CONSTRAINT PK_FACILITY PRIMARY KEY (FACILITY_ID)
)
INSERT INTO TBL_FACILITY (FAMILY_HEAD_ID, FACILITY_SELECTED, FACILITY_USED)
VALUES (121, 1, '2,6'), (122, 1, '5'), (123, 1, '5,6');
The format of final result:
121 communication laptop
121 communication smart phone
122 communication iphone
123 communication iphone
123 communication smart phone
How can I get this result?
Presuming ,as an identity column, tbl_reference.ref_number columns' values are 1,2,3,4,5,6,7 in downwards order , by the contribution of SUBSTRING and CHARINDEX string operators, you may use the following SQL :
SELECT family_head_id, ref_name+' '+ref_value reference
FROM TBL_FACILITY INNER JOIN TBL_REFERENCE
ON ( ref_number = SUBSTRING(facility_used,CHARINDEX(',', facility_used)-1,1) )
UNION ALL
SELECT family_head_id, ref_name+' '+ref_value reference
FROM TBL_FACILITY INNER JOIN TBL_REFERENCE
ON ( ref_number = SUBSTRING(facility_used,CHARINDEX(',', facility_used)+1,1) )
ORDER BY 1, 2;
SQL Fiddle Demo

INSERT INTO table_name VALUES (value1, value2, value3, ...);How to transfer a data of a single column in a single table row

Hi guys I'm working on a vanilla system where we can add many systems in it with data sets and fields. we can add fields and data of each system at run time without changing the structure of database.
CREATE TABLE Type(
ID int,
Name varchar(255),
PRIMARY KEY (ID)
);
INSERT INTO Type VALUES (1, 'cust_obj_7');
INSERT INTO Type VALUES (2, 'cust_obj_8');
CREATE TABLE Object(
ID int,
Name varchar(255),
Description varchar(255),
TypeID int,
PRIMARY KEY (ID),
FOREIGN KEY (TypeID ) REFERENCES Type(ID)
);
INSERT INTO Object VALUES (1, 'First', 'First_desc', 1);
INSERT INTO Object VALUES (2, 'Second', 'Second_desc', 1);
CREATE TABLE TypeFields(
ID int,
Name varchar(255),
NameType varchar(255),
TypeID int,
PRIMARY KEY (ID),
FOREIGN KEY (TypeID ) REFERENCES Type(ID)
);
INSERT INTO TypeFields VALUES (1, 'First', 'str', 1);
INSERT INTO TypeFields VALUES (2, 'Seond', 'str', 1);
INSERT INTO TypeFields VALUES (3, 'Third', 'int', 1);
CREATE TABLE FieldsData(
ID int,
ObjectID int,
FieldID int,
FieldName varchar(255),
TypeID int,
value varchar(255),
PRIMARY KEY (ID),
FOREIGN KEY (TypeID ) REFERENCES Type(ID),
FOREIGN KEY (ObjectID ) REFERENCES Object(ID),
FOREIGN KEY (FieldID ) REFERENCES TypeFields(ID)
);
INSERT INTO VALUES (1, 1, 1, 'First', 1, "a");
INSERT INTO VALUES (2, 1, 2, 'Second', 1, "b");
INSERT INTO VALUES (3, 1, 3, 'Third', 1, "120");
INSERT INTO VALUES (4, 2, 1, 'First', 1, "c");
INSERT INTO VALUES (5, 2, 2, 'Second', 1, "d");
INSERT INTO VALUES (6, 2, 3, 'Third', 1, "130");
CREATE TABLE FinalTable(
ObjID int,
ObjName varchar(255),
ObjDesc varchar(255),
First varchar(255),
Second varchar(255),
Third int
);
Data will look like this
Insert Into FinalTable
select *
from object, fieldsdata
where object.iD = fieldsdata.objectiD
Values(object.ID , object.Name, object.Description, ....... );
I want to create a single data set form these tables as finaltable as shown above. I can get all the data using keys but I'm having issue to write that data to a single row from a column of different rows. I'm stuck that how can I achieve this using sql in sas-base.
First, "My custom table" should be a view originating from "Fields data". "Fields data" is a bit of a misnomer because it contains the values of the fields. So in an abstraction that distinction is important for understanding within the framework you are building.
A row in "My custom table" appears to be for projecting TypeID=1. You don't show other TypeID values, but I presume they would be for different custom tables.
The custom tables should really be views, otherwise each object is a potential +1 to a multiplier regarding storage requirements
In your sample image the second row of "My custom table" has ObjID=2, yet shows values from the "Fields data" that correspond to ObjID=2. I will presume a typo.
The "Object types" name is not rendered in the Custom table, thus I would consider it simply a catalog of types.
The design you present is not a normal form yet. Not sure why FieldName is replicated in "Fields data", you have the FieldID that refers to a record with the name. Not sure why TypeID is present in "Fields data" because TypeID is essentially a catalog item selector for the desired projection of the "Fields data"
This kind of design can cause a lot of reinvention and will take huge amounts of time to flesh out for different value types such as dates, value rendering formats, multivalued types, etc...
Regardless, the projection of the values data as an object type to a custom table is essentially a transposition of a join that combines object, type fields, and fields data. SAS SQL does not have a PIVOT operator (such as is found in MS SQL Server). The 'old school' way to pivot in SQL involves aggregating case statements over a by group. Search SO
There are some designs for an 'arbitrarium' that simply kill all the middle men and have a single enormous values monolith with say 20 ID fields, 1,000 numeric fields, 1,000 character fields and 100 date fields and each 'object' is a use-case SQL view against it.
** EDIT - ADDED BELOW **
Added code demonstrating 'old school' pivot:
PROC SQL;
CREATE TABLE Type(
ID int,
Name varchar(255)/*,
PRIMARY KEY (ID)*/
);
INSERT INTO Type VALUES (1, 'cust_obj_7');
INSERT INTO Type VALUES (2, 'cust_obj_8');
CREATE TABLE Object(
ID int,
Name varchar(255),
Description varchar(255),
TypeID int/*,
PRIMARY KEY (ID),
FOREIGN KEY (TypeID ) REFERENCES Type(ID);*/
);
INSERT INTO Object VALUES (1, 'First', 'First_desc', 1);
INSERT INTO Object VALUES (2, 'Second', 'Second_desc', 1);
CREATE TABLE TypeFields(
ID int,
Name varchar(255),
NameType varchar(255),
TypeID int/*,
PRIMARY KEY (ID),
FOREIGN KEY (TypeID ) REFERENCES Type(ID) */
);
INSERT INTO TypeFields VALUES (1, 'First', 'str', 1);
INSERT INTO TypeFields VALUES (2, 'Seond', 'str', 1);
INSERT INTO TypeFields VALUES (3, 'Third', 'int', 1);
CREATE TABLE FieldsData(
ID int,
ObjectID int,
FieldID int,
FieldName varchar(255),
TypeID int,
value varchar(255)/*,
PRIMARY KEY (ID),
FOREIGN KEY (TypeID ) REFERENCES Type(ID),
FOREIGN KEY (ObjectID ) REFERENCES Object(ID),
FOREIGN KEY (FieldID ) REFERENCES TypeFields(ID)*/
);
INSERT INTO FieldsData VALUES (1, 1, 1, 'First', 1, "a");
INSERT INTO FieldsData VALUES (2, 1, 2, 'Second', 1, "b");
INSERT INTO FieldsData VALUES (3, 1, 3, 'Third', 1, "120");
INSERT INTO FieldsData VALUES (4, 2, 1, 'First', 1, "c");
INSERT INTO FieldsData VALUES (5, 2, 2, 'Second', 1, "d");
INSERT INTO FieldsData VALUES (6, 2, 3, 'Third', 1, "130");
CREATE TABLE FinalTable(
ObjID int PRIMARY KEY,
ObjName varchar(255),
ObjDesc varchar(255),
First varchar(255),
Second varchar(255),
Third int
);
create view example_type1_realized as
select
FieldsData.ObjectID as ObjID
, max(Object.Name) as ObjName
, max(Object.Description) as ObjDesc
, max(case when FieldID=1 then Value end) as First
, max(case when FieldID=2 then Value end) as Second
, max(case when FieldID=3 then input(Value,best12.) end) as Third
from FieldsData
join Object
on FieldsData.ObjectID = Object.ID
where TypeID = 1
group by ObjID
;
Now, for each TypeID you will need to construct a code generator that can create the source code wallpaper ... max(case when ... construct. from the TypeFields data.
Here is one way:
* Now a codegener macro that can produce the example realization: ;
%macro realize (TypeID=, out=);
%local wallpaper;
proc sql noprint;
select cat
(
', max(case when FieldID=', cats(ID), ' then '
, case
when NameType='str' then 'Value'
when NameType='int' then 'input(Value,12.)'
else 'cats(Value) || " (' || NameType || ') unhandled"'
end
, ' end)'
, ' as ', Name
) length=32000
into :wallpaper separated by ' '
from TypeFields
where TypeID = &TypeID
;
%put NOTE: wallpaper=%SUPERQ(wallpaper);
create &out as
select
FieldsData.ObjectID as ObjID
, max(Object.Name) as ObjName
, max(Object.Description) as ObjDesc
&wallpaper
from FieldsData
join Object
on FieldsData.ObjectID = Object.ID
group by ObjID
;
quit;
%mend;
options mprint;
%realize(TypeID=1, out=table type1_replicate)
You can modify the codegener so that it will insert rows into an out= instead of creating anew.
You should see that your system is workable but needs alot of attention to become generic. Each FieldType might get format, informat, length, date handling, error handling for out-of-range values for type, field sequence, etc...

Importing into Gender Field in SQL/SSIS

How would you handle importing only male (m) or female (f) data into a gender field, so that it won't get populated with any potential extraneous source data, in SQL or SSIS?
You can create a column constraint:
CREATE TABLE Persons
(
Id int NOT NULL,
LastName varchar(255),
FirstName varchar(255),
Gender varchar(1),
CONSTRAINT chk_Gender CHECK (Gender ='m' or Gender='f')
)
Insert into Persons values(1,'smith', 'jane', 'f');
insert into Persons values(2,'smith', 'john', SUBSTRING('male', 1, 1));
/* this will fail
INSERT INTO Persons values (3,'foo', 'bar', 'u');
*/
select * FROM Persons;
Working Fiddle
It's trival to add a check constraint, something like:
CREATE TABLE #Test (
GENDER CHAR(1) CONSTRAINT Constraint_Gender CHECK (GENDER IN ('A','B','C'))
)
INSERT INTO #Test VALUES ('A')
INSERT INTO #Test VALUES ('D')
(1 row(s) affected)
Msg 547, Level 16, State 0, Line 9
The INSERT statement conflicted with the CHECK constraint "Constraint_Gender".
However, you should really cater for non-binary genders in a similar manner to facebook etc https://www.facebook.com/facebookdiversity/posts/774221582674346 (hence A, B, C in my example above)

How to create an "on-the-fly" mapping table within a SELECT statement in Postgresql

I'm creating a select statement that combines two tables, zone and output,
based on a referenced device table and on a mapping of zone_number to output_type_id.
The mapping of zone_number to output_type_id doesn't appear
anywhere in the database, and I would like to create it "on-the-fly" within the select
statement. Below is my schema:
CREATE TABLE output_type (
id INTEGER NOT NULL,
name TEXT,
PRIMARY KEY (id)
);
CREATE TABLE device (
id INTEGER NOT NULL,
name TEXT,
PRIMARY KEY (id)
);
CREATE TABLE zone (
id SERIAL NOT NULL,
device_id INTEGER NOT NULL REFERENCES device(id),
zone_number INTEGER NOT NULL,
PRIMARY KEY (id),
UNIQUE (zone_number)
);
CREATE TABLE output (
id SERIAL NOT NULL,
device_id INTEGER NOT NULL REFERENCES device(id),
output_type_id INTEGER NOT NULL REFERENCES output_type(id),
enabled BOOLEAN NOT NULL,
PRIMARY KEY (id)
);
And here is some example data:
INSERT INTO output_type (id, name) VALUES
(101, 'Output 1'),
(202, 'Output 2'),
(303, 'Output 3'),
(404, 'Output 4');
INSERT INTO device (id, name) VALUES
(1, 'Test Device');
INSERT INTO zone (device_id, zone_number) VALUES
(1, 1),
(1, 2),
(1, 3),
(1, 4);
INSERT INTO output (device_id, output_type_id, enabled) VALUES
(1, 101, TRUE),
(1, 202, FALSE),
(1, 303, FALSE),
(1, 404, TRUE);
I need to get the associated enabled field from the output table for each zone for a given device.
Each zone_number maps to an output_type_id. For this example:
zone_number | output_type_id
----------------------------
1 | 101
2 | 202
3 | 303
4 | 404
One way to handle the mapping would be to create a new table
CREATE TABLE zone_output_type_map (
zone_number INTEGER,
output_type_id INTEGER NOT NULL REFERENCES output_type(id)
);
INSERT INTO zone_output_type_map (zone_number, output_type_id) VALUES
(1, 101),
(2, 202),
(3, 303),
(4, 404);
And use the following SQL to get all zones, plus the enabled flag, for device 1:
SELECT zone.*, output.enabled
FROM zone
JOIN output
ON output.device_id = zone.device_id
JOIN zone_output_type_map map
ON map.zone_number = zone.zone_number
AND map.output_type_id = output.output_type_id
AND zone.device_id = 1
However, I'm looking for a way to create the mapping of zone nunbers to output
types without creating a new table and without piecing together a bunch of AND/OR
statements. Is there an elegant way to create a mapping between the two fields
within the select statement? Something like:
SELECT zone.*, output.enabled
FROM zone
JOIN output
ON output.device_id = zone.device_id
JOIN (
SELECT (
1 => 101,
2 => 202,
3 => 303,
4 => 404
) (zone_number, output_type_id)
) as map
ON map.zone_number = zone.zone_number
AND map.output_type_id = output.output_type_id
AND zone.device_id = 1
Disclaimer: I know that ideally the enabled field would exist in the zone
table. However, I don't have control over that piece. I'm just looking for the
most elegant solution from the application side. Thanks!
You can use VALUES as an inline table and JOIN to it, you just need to give it an alias and column names:
join (values (1, 101), (2, 202), (3, 303), (4, 304)) as map(zone_number, output_type_id)
on ...
From the fine manual:
VALUES can also be used where a sub-SELECT might be written, for
example in a FROM clause:
SELECT f.*
FROM films f, (VALUES('MGM', 'Horror'), ('UA', 'Sci-Fi')) AS t (studio, kind)
WHERE f.studio = t.studio AND f.kind = t.kind;
UPDATE employees SET salary = salary * v.increase
FROM (VALUES(1, 200000, 1.2), (2, 400000, 1.4)) AS v (depno, target, increase)
WHERE employees.depno = v.depno AND employees.sales >= v.target;
So just to complement the accepted answer, the following code is a valid, self-contained Postgresql expression which will evaluate to an 'inline' relation with columns (zone_number, output_type_id):
SELECT * FROM
(VALUES
(1, 101),
(2, 202),
(3, 303),
(4, 304)
) as i(zone_number, output_type_id)
(The (VALUES ... AS ...) part alone will not make a valid expression, which is why I added the SELECT * FROM.)
JOIN
(SELECT 1 zone_number, 101 as output_type_id
UNION ALL
SELECT 2 zone_number, 202 as output_type_id
UNION ALL
SELECT 3 zone_number, 303 as output_type_id
) mappings on mappings.zone_number = zone.zone_number