component 'DEPARTMENT_ID' must be declared PLSQL - database

I have the following code.
DECLARE
TYPE t_dep IS TABLE OF DEPARTMENTS%ROWTYPE
INDEX BY BINARY_INTEGER;
v_dep t_dep;
BEGIN
FOR dep_rec IN
(SELECT department_name, location_id FROM Departments
ORDER BY department_id ASC)
LOOP
v_dep(dep_rec.department_id) := dep_rec;
END LOOP;
END;
And I get this error:
Error report -
ORA-06550: line 10, column 23:
PLS-00302: component 'DEPARTMENT_ID' must be declared
ORA-06550: line 10, column 9:
PL/SQL: Statement ignored
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
This is the departments table.
Here is my task:
Write an anonymous PL/SQL block that declares and populates an INDEX BY table of records containing
department data. The table of records should use the departmentid as a primary key, and each element should
contain department name and location id. The data should be stored in the INDEX BY table of records in ascending
sequence of departmentid. The block should not display any output.
How can I deal with this error?

When you create your loop over this implict cursor
SELECT department_name, location_id
FROM Departments
ORDER BY department_id ASC
you say that you are only interested in the columns department_name, location_id.
If you even need ID, you have to add it to the select list:
SELECT department_name, location_id, department_id
Also, your structure is defined as
TABLE OF DEPARTMENTS%ROWTYPE
so you need all the coumns of the table, in the right order, to populate it: you need manager_id too.
Another point: if you define a structure as INDEX BY BINARY_INTEGER, you have to use a binary integer to index it; are you sure department_id is a binary index?

DEP_REC contains department_name and location_id, while you're using department_id in this statement:
v_dep(dep_rec.department_id) := dep_rec;
-------------
As it doesn't exist, your code fails.
How to fix it? Include department_id into cursor FOR loop's SELECT statement.
Also, as DEPARTMENTS table contains 4 columns, you'll have to select them all in order to make it work (currently, MANAGER_ID is missing).

Related

SQL Server changes the value in the float column when converting to varchar

I have a column in my table that is of float type. The table was automatically generated when I imported the spreadsheet (Excel) data to my database. Thus there is a column I wish to change from float to varchar, but when I try to do this, I get an error:
'tblInvoices' table
Unable to create index 'IX_tblInvoices'.
The CREATE UNIQUE INDEX statement terminated because a duplicate key was found for the object name 'dbo.tblInvoices' and the index name 'IX_tblInvoices'.
The duplicate key value is (1.00001e+006). The statement has been terminated.
It is a unique column, and set that way (not set as the primary key for reasons). I have already run queries to search for and delete duplicate fields but there are none. The query I ran as follows:
WITH CTE AS
(
SELECT
Invoice,
RN = ROW_NUMBER()OVER(PARTITION BY Invoice ORDER BY Invoice)
FROM
dbo.tblInvoices
)
DELETE FROM CTE
WHERE RN > 1
So the value within the Invoice column is 1000010 and when I run the following query a single row is found.
SELECT *
FROM [TradeReceivables_APR_IFRS9].[dbo].[tblInvoices]
WHERE Invoice = 1.00001e+006
Note that I have searched for the value in the error, 1.00001e+006, and not 1000010.
So my question is why does the DBMS do this? Why does it change the value like that? When I remove the column, it does it with another column and so on and so on (about 40 000 rows in total). How can I change the column from float to varchar without changing the data and getting errors?
Any help will be greatly appreciated!
It seems that the field is an integer so you can Cast it to BIGINT before cast to VARCHAR
Declare #Invoice as float = 1.00001e+006
print cast(#Invoice as varchar) -->> Result : 1.00001e+006
print cast(cast(#Invoice as bigint) as varchar) -->> Result : 1000010

Indexed view - SUM function that references a nullable expression

I have table with time entries with following columns:
Id (PK)
Date
EmployeeId
State (state of the entry New, Approved, etc.)
Quantity
And I would like to create an indexed view which groups time entries by day and employee. So I used:
CREATE VIEW dbo.Test1
WITH SCHEMABINDING
AS
SELECT
Date, EmployeeId, SUM(Quantity), SUM(CASE State = 1 THEN Quantity ELSE NULL END) AS QuantityApproved
FROM
TimeEntries
GROUP BY
EmployeeId, Date
CREATE UNIQUE CLUSTERED INDEX IDX_V1
ON dbo.Test1 (EmployeeId, Date);
GO
But when I try to make it an indexed view an error occurs:
Cannot create the clustered index "IDX_V1" on view "dbo.Test1" because the view references an unknown value (SUM aggregate of nullable expression). Consider referencing only non-nullable values in SUM. ISNULL() may be useful for this.
Obviously using ISNULL would help in case of QuantityApproved column. But this is not a solution for me as 0 may also indicate there are 2 records (Quantity=-1 and QUantity=1) on the same day.
Also I can use an auxiliary column for ABS value for this case, but having NULL there is very convenvient as I do not need to solve anything else.
Is there any other way to overcome this?

T-SQL GROUP BY a nvarchar error

I was wondering if anyone could help me with a request kindly:
Here is the data:
Table 1: EMPLOYEE
FK: DID
PK: Name
UserName
Table 2: DEPARTMENT
PK: DID
TerminationDate
I’m looking to find the number of terminated employees in the quarter. Here is the T-SQL so far:
SELECT
DEPARTMENT.name AS Name,
COUNT(e.userName)
FROM
EMPLOYEE AS e
JOIN
DEPARTMENT ON e.department = DEPARTMENT.DID
UNION
SELECT
u.eu, u.name
FROM
(SELECT
dd.name, COUNT(ee.userName) AS eu
FROM
DEPARTMENT AS dd
JOIN
EMPLOYEE AS ee ON dd.DID = ee.department
AND ee.terminationDate IS NOT NULL
WHERE
ee.terminationDate IS NOT NULL
AND ee.terminationDate BETWEEN '2015-04-01' AND '2015-06-30'
GROUP BY
dd.name, ee.userName) AS u
GROUP BY
u.eu, u.name, Name
ORDER BY
Name
The error is:
Msg 8120, Level 16, State 1, Line 1
Column 'DEPARTMENT.name' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
In the first part of your query, you list the department name in your select clause but don't include it in a group by clause (because it is missing)
select DEPARTMENT.name as Name, COUNT(e.userName)
from EMPLOYEE as e
join DEPARTMENT on e.department = DEPARTMENT.DID
group by DEPARTMENT.Name --add this line
The number of problems with this query are bewildering. To start with... The table definitions you have listed do not match your query. You have the TerminationDate as an attribute of the DEPARTMENT table, where as in the query it looks like you are accessing it though the EMPLOYEE table, which makes sense to be there. So I'm going to assume that your table structure really is:
Table 1: EMPLOYEE
FK: DID
PK: Name
UserName
TerminationDate
Table 2: DEPARTMENT
PK: DID
Name
The way you have used a UNION in this query leads me to believe that you have a misunderstanding of what a UNION statement does. UNION is used to join two sets into one. So in set theory {1,2,3} union {3, 4} is {1,2,3,3,4}. In SQL Server, you have to make sure that the types and number of columns in the first select statement match all the selects that are unioned with it. So for example:
Select 1 A, 2 B
Union
Select 3 B
Will give this error because the first select has two columns and the second has only one:
Msg 205, Level 16, State 1, Line 3 All queries combined using a UNION,
INTERSECT or EXCEPT operator must have an equal number of expressions
in their target lists.
And this query:
Select 1 A
Union
Select 'Bob' A
Will give this error because the column types do not match:
Msg 245, Level 16, State 1, Line 2 Conversion failed when converting
the varchar value 'Bob' to data type int.
If all you are looking for is the number of employees terminated between two dates, then there really isn't really anything you need to union. All the employees are already together in one set (the Employee table)... and you just need to filter the dates you want and count the record total. You don't even need the DEPARTMENT table to calculate this.
I could write the query for you... but I'll leave the rest to you.

TSQL: getting next available ID

Using SQL Server 2008, have three tables, table a, table b and table c.
All have an ID column, but for table a and b the ID column is an identity integer, for table c the ID column is a varchar type
Currently a stored procedure take a name param, following certain logic, insert to table a or table b, get the identity, prefix with 'A' or 'B' then insert to table c.
Problem is, table C ID column potentially have the duplicated values, i.e. if identity from table A is 2, there might already have 'A2','A3','A5' in the ID column for table C, how to write a T-SQL query to identify the next available value in table C then ensure to update table A/B accordingly?
[Update]
this is the current step,
1. depends on input parameter, insert to table A or table B
2. initialize seed value = ##Identity
3. calculate ID value to insert to table C by prefix 'A' or append 'B' with the seed value
4. look for record match in table C by ID value from step 3, if didn't find any record, insert it, else increase seed value by 1 then repeat step 3
The issue being at a certain value range, there could be a huge block of value exists in table C ID, i.e. A3000 to A500000 existed now in table C ID, the database query is extemely slow if follow the existing logic. Needs to figure out a logic to smartly get the minimum available number (without the prefix)
it is hard to describe, hope this make more sense, I truly appreciate any help on this Thanks in advance!
This should do the trick. Simple self extracting example will work in SSMS. I even made it out of order just in case. You would just change your table to be where #Data is and then change Identifier field to replace 'ID'.
declare #Data Table ( Id varchar(3) );
insert into #Data values ('A5'),('A2'),('B1'),('A3'),('B2'),('A4'),('A1'),('A6');
With a as
(
Select
ID
, cast(right(Id, len(Id)-1) as int) as Pos
, left(Id, 1) as TableFrom
from #Data
)
select
TableFrom
, max(Pos) + 1 as NextNumberUp
from a
group by TableFrom
EDIT: If you want to not worry about production data you could add this last part amending what I wrote:
Select
TableFrom
, max(Pos) as LastPos
into #Temp
from a
group by TableFrom
select TableFrom, LastPos + 1
from #Temp
Regardless if this was production environment you are going to have to hit part of it at some time to get data. If the datasets are not too large and just varchar(256) or less and only 5 million rows or less you could dump that entire column from tableC to a temp table. Honestly query performance versus imports change vastly from system to system.
Following your design there shouldn't be any duplicates in Table C considering that A and B are unique.
A | B | C
1 1 A1
2 2 A2
B1
B2

Inserting data into one column fails saying values in another column can't be null

I can't understand this misunderstanding by SQL Server.
As you can see, I'm trying to insert into column Ordamount, but SQL Server shows me in its error message that it can't insert null into column UserID?
Declare #variable1 int =( select sum(Orr.quantity *OI.Iteprice)
from Orderrouter Orr
inner join OrdItem OI on Orr.OrdItems =OI.ItemId
where OrdId = 1)
insert into Ord (Ordamount)
values (#variable1);
Error:
Msg 515, Level 16, State 2, Line 6 Cannot insert the value
NULL into column 'UserID', table 'Example.dbo.Ord'; column does
not allow nulls. INSERT fails.
The statement has been terminated.
For columns in the Ord table that does not allow null by default, you have to provide value for, you cannot skip them. You have to provide value for UserID if it's not Nullable unless it's an identity column
I think the problem is that you only specify the amount when inserting which isn't the primary key in the table, might be an idea to show how the table looks as well. An auto increment on the id column migh solve the problem
Please use a more descriptive title.
Beside this, it seems that the Ord.UserID field is not initialized. Maybe it is not an autoincrement.
Try with this, specifying the UserId value:
INSERT into Ord values(<UserId value here>, #Varaible1)

Resources