insert data from multiple fields of similar information into fewer fields - ms-access-2007

I inherited a legacy ms access database. I have one table with 30 fields of similar information.
JobID CityM1 StateM1 CityM2 StateM2 CityM3 StateM3 CityP1 StateP1 CityP2 StateP2.........
What I want to do is reduce the information to the following fields:
JobID.....Description (M or P).....City.....State
How do I use SQL to insert the data from all the related fields into the new table format. Thanks for any suggestions.

Probably I would do the following:
If the old table is jobs_old(....) and new table is jobs_new(jobid, city, state, description), the primary key could be on jobid and city or jobid, city and state if city name is not unique in each state. You may have some other column to make the unique based on the normalization form.
Then I would execute a series of INSERT INTO jobs_new ... SELECT...FROM jobs_old to populate data into the new table by selecting data from appropriate columns from the old table. Examples:
INSERT INTO jobs_new(jobid, city, state, description)
SELECT jobid, CityM1, StateM1, 'M' FROM jobs_old;
INSERT INTO jobs_new(jobid, city, state, description)
SELECT jobid, CityM2, StateM2, 'M' FROM jobs_old;
...
INSERT INTO jobs_new(jobid, city, state, description)
SELECT jobid, CityP1, StateP2, 'P' FROM jobs_old;
...
Note that I am hoping the statement syntax is accepted in MSACCESS! Otherwise, you have to use some other technique.
The table definition could be something like as following (used sqlcmd tool of MS SQL server):
1> CREATE TABLE jobs_new (jobid INT NOT NULL,
2> city VARCHAR(50) NOT NULL, state CHAR(2) NOT NULL,
3> description CHAR(1) NOT NULL,
4> PRIMARY KEY(jobid, city, state)
5> );
6> go
1>
Use appropriate data types for columns as per your requirements and change primary key columns as required.

Related

ID generation in Oracle

I'm trying to create a table in Oracle as follows:
create table person (
person_id number(5) generated always as identity
minvalue 1
maxvalue 99999
increment by 1 start with 1
cycle
cache 10,
firstname varchar(10),
lastname varchar(10));
This works all fine, but when I try something like this:
insert into person
values ('firstname', 'lastname');
I'm getting an error. When I try putting in a number where the ID should be, I get a different error.
I'm confused because I originally thought that formatting the person_id in this way automatically generated unique ID values, so that I wouldn't be able to put them in.
I'm also a bit confused on how this all fits into JDBC. If I'm working with Java and I insert a tuple into such a table, how am I able to get the generated ID into my Java program? I can't search by first and last name, because there could be two people with the same name.
You need to list the columns for an insert:
insert into person(firstname, lastname)
values ('firstname', 'lastname');
The fact that the column is generated doesn't affect the syntax of the insert. So, with no columns, the insert is the same as:
insert into person(person_id, firstname, lastname)
values ('firstname', 'lastname');
And with two values and three columns, you are getting an error.

Optional Unique Constraints?

I am setting up a SaaS application that multiple clients will use to enter data. However, I have certain fields that Client A may want to force unique, Client B may want to allow dupes. Obviously if I am going to allow any one client to have dupes, the table may not have a unique constraint on it. The downside is that If I want to enforce a unique constraint for some clients, I will have to go about it in some other way.
Has anyone tackled a problem like this, and if so, what are the common solutions and or potential pitfalls to look out for?
I am thinking a trigger that checks for any possible unique flags may be the only way to enforce this correctly. If I rely on the business layer, there is no guarentee that the app will do a unique check before every insert.
SOLUTION:
First I considered the Unique Index, but ruled it out as they can not do any sort of joins or lookups, only express values. And I didn't want to modify the index every time a client was added or a client's uniqueness preference changed.
Then I looked into CHECK CONSTRAINTS, and after some fooling around, built one function to return true for both hypothetical columns that a client would be able to select as unique or not.
Here is the test tables, data, and function I used to
verify that a check constraint could do all that I wanted.
-- Clients Table
CREATE TABLE [dbo].[Clients](
[ID] [int] NOT NULL,
[Name] [varchar](50) NOT NULL,
[UniqueSSN] [bit] NOT NULL,
[UniqueVIN] [bit] NOT NULL
) ON [PRIMARY]
-- Test Client Data
INSERT INTO Clients(ID, Name, UniqueSSN, UniqueVIN) VALUES(1,'A Corp',0,0)
INSERT INTO Clients(ID, Name, UniqueSSN, UniqueVIN) VALUES(2,'B Corp',1,0)
INSERT INTO Clients(ID, Name, UniqueSSN, UniqueVIN) VALUES(3,'C Corp',0,1)
INSERT INTO Clients(ID, Name, UniqueSSN, UniqueVIN) VALUES(4,'D Corp',1,1)
-- Cases Table
CREATE TABLE [dbo].[Cases](
[ID] [int] IDENTITY(1,1) NOT NULL,
[ClientID] [int] NOT NULL,
[ClaimantName] [varchar](50) NOT NULL,
[SSN] [varchar](12) NULL,
[VIN] [varchar](17) NULL
) ON [PRIMARY]
-- Check Uniques Function
CREATE FUNCTION CheckUniques(#ClientID int)
RETURNS int -- 0: Ok to insert, 1: Cannot insert
AS
BEGIN
DECLARE #SSNCheck int
DECLARE #VinCheck int
SELECT #SSNCheck = 0
SELECT #VinCheck = 0
IF (SELECT UniqueSSN FROM Clients WHERE ID = #ClientID) = 1
BEGIN
SELECT #SSNCheck = COUNT(SSN) FROM Cases cs WHERE ClientID = #ClientID AND (SELECT COUNT(SSN) FROM Cases c2 WHERE c2.SSN = cs.SSN) > 1
END
IF (SELECT UniqueVIN FROM Clients WHERE ID = #ClientID) = 1
BEGIN
SELECT #VinCheck = COUNT(VIN) FROM Cases cs WHERE ClientID = #ClientID AND (SELECT COUNT(VIN) FROM Cases c2 WHERE c2.VIN = cs.VIN) > 1
END
RETURN #SSNCheck + #VinCheck
END
-- Add Check Constraint to table
ALTER TABLE Cases
ADD Constraint chkClientUniques CHECK(dbo.CheckUniques(ClientID) = 0)
-- Now confirm constraint using test data
-- Client A: Confirm that both duplicate SSN and VIN's are allowed
INSERT INTO Cases (ClientID, ClaimantName, SSN, VIN) VALUES(1, 'Alice', '111-11-1111', 'A-1234')
INSERT INTO Cases (ClientID, ClaimantName, SSN, VIN) VALUES(1, 'Bob', '111-11-1111', 'A-1234')
-- Client B: Confirm that Unique SSN is enforced, but duplicate VIN allowed
INSERT INTO Cases (ClientID, ClaimantName, SSN, VIN) VALUES(2, 'Charlie', '222-22-2222', 'B-2345') -- Should work
INSERT INTO Cases (ClientID, ClaimantName, SSN, VIN) VALUES(2, 'Donna', '222-22-2222', 'B-2345') -- Should fail
INSERT INTO Cases (ClientID, ClaimantName, SSN, VIN) VALUES(2, 'Evan', '333-33-3333', 'B-2345') -- Should Work
-- Client C: Confirm that Unique VIN is enforced, but duplicate SSN allowed
INSERT INTO Cases (ClientID, ClaimantName, SSN, VIN) VALUES(3, 'Evan', '444-44-4444', 'C-3456') -- Should work
INSERT INTO Cases (ClientID, ClaimantName, SSN, VIN) VALUES(3, 'Fred', '444-44-4444', 'C-3456') -- Should fail
INSERT INTO Cases (ClientID, ClaimantName, SSN, VIN) VALUES(3, 'Ginny', '444-44-4444', 'C-4567') -- Should work
-- Client D: Confirm that both Unique SSN and VIN are enforced
INSERT INTO Cases (ClientID, ClaimantName, SSN, VIN) VALUES(4, 'Henry', '555-55-5555', 'D-1234') -- Should work
INSERT INTO Cases (ClientID, ClaimantName, SSN, VIN) VALUES(4, 'Isaac', '666-66-6666', 'D-1234') -- Should fail
INSERT INTO Cases (ClientID, ClaimantName, SSN, VIN) VALUES(4, 'James', '555-55-5555', 'D-2345') -- Should fail
INSERT INTO Cases (ClientID, ClaimantName, SSN, VIN) VALUES(4, 'Kevin', '555-55-5555', 'D-1234') -- Should fail
INSERT INTO Cases (ClientID, ClaimantName, SSN, VIN) VALUES(4, 'Lisa', '777-77-7777', 'D-3456') -- Should work
EDIT:
Had to modify the function a few times to catch NULL values in the dupe check, but all appears to be working now.
One approach is to use a CHECK constraint instead of a unique.
This CHECK constraint will be backed by a SCALAR function that will
take as input ClientID
cross-ref ClientID against a lookup table to see if duplicates are allowed (client.dups)
if not allowed, check for duplicates in the table
Something like
ALTER TABLE TBL ADD CONSTRAINT CK_TBL_UNIQ CHECK(dbo.IsThisOK(clientID)=1)
If you can identify rows in the table for each client, depending on your DBMS you could do something like this:
CREATE UNIQUE INDEX uq_some_col
ON the_table(some_column, other_column, client_id)
WHERE client_id IN (1,2,3);
(The above is valid for PostgreSQL and and I think SQL Server 2005)
The downsize is, that you will need to re-create that index each time a new client is added that requires those columns to be unique.
You will probably have some checks in the business layer as well, mostly to be able to show proper error messages.
That's perfectly possible now on Sql Server 2008(tested on my Sql Server 2008 box here):
create table a
(
cx varchar(50)
);
create unique index ux_cx on a(cx) where cx <> 'US';
insert into a values('PHILIPPINES'),('JAPAN'),('US'),('CANADA');
-- still ok to insert duplicate US
insert into a values('US');
-- will fail here
insert into a values('JAPAN');
Related article: http://www.ienablemuch.com/2010/12/postgresql-said-sql-server2008-said-non.html
There are a few things you can do with this, just depends on when/how you want to handle this.
You could use a CheckConstrain and modify this to do different lookups based on the client that was using it
You could use the business tier to handle this, but it will not protect you from raw database updates.
I personally have found that #1 can get too hard to maintain, especially if you get a high number of clients. I've found that doing it at the business level is a lot easier, and you can control it at a centralized location.
Thee are other options such as a table per client and others that could work as well, but these two are at least the most common that I've seen.
You could add a helper column. The column would be equal the the primary key for the application that allows duplicates, and a constant value for the other application. Then you create a unique constraint on UniqueHelper, Col1.
For the non-dupe client, it will have a constant in the helper column, forcing the column to be unique.
For the dupe column, the helper column is equal to the primary key, so the unique constraint is satisfied by that column alone. That application can add any number of dupes.
One possibility might be to use BEFORE INSERT and and BEFORE UPDATE triggers that can selectively enforce uniqueness.
And another possibility (kind of a kludge) would be to have an additional dummy field that is populated with unique values for one customer and duplicate values for the other customer. Then build a unique index on the combination of the dummy field and the visible field.
#Neil. I had asked in my comment above what your reasons were for putting all in the same table and you simply ignored that aspect of my comment and said everything was "plain and simple". Do you really want to hear the downsides of the conditional constraints approach in an Saas context?
You don't say how many different sets of rules this table in your Saas application may eventually need to incorporate. Will there be only two variations?
Performance is a consideration. Although each customer would have access to a dedicated conditional index|indices, fetching data from the base table could become slower and slower as the data from additional customers is added to it and the table grows.
If I were developing an Saas application, I'd go with dedicated transaction tables wherever appropriate. Customers could share standard tables like zipcodes, counties, and share even domain-specific tables like Products or Categories or WidgetTypes or whatever. I'd probably build dynamic SQL statements in stored procedures in which the correct table for the current customer was chosen and placed in the statement being constructed, e.g.
sql = "select * from " + DYNAMIC_ORDERS_TABLE + " where ... ")
If performance was taking a hit because the dynamic statements had to be compiled all the time, I might consider writing a dedicated stored procedure generator: sp_ORDERS_SELECT_25_v1.0 {where "25" is the id assigned to a particular user of the Saas app and there's a version suffix}.
You're going to have to use some dynamic SQL because the customer id must be appended to the WHERE-clause of every one of your ad hoc queries in order to take advantage of your conditional indexes:
sql = " select * from orders where ... and customerid = " + CURRENT_CUSTOMERID
Your conditional indexes involve your customer/user column and so that column must be made part of every query in order to ensure that only that customer's subset of rows are selected out of the table.
So, when all is said and done, you're really saving yourself the effort required to create a dedicated table and avoiding some dynamic SQL on your bread-and-butter queries. Writing dynamic SQL for bread-and-butter queries doesn't take much effort, and it's certainly less messy than having to manage multiple customer-specific indexes on the same shared table; and if you're writing dynamic SQL you could just as easily substitute the dedicated table name as append the customerid=25 clause to every query. The performance loss of dynamic SQL would be more than offset by the performance gain of dedicated tables.
P.S. Let's say your app has been running for a year or so and you have multiple customers and your table has grown large. You want to add another customer and their new set of customer-specific indexes to the large production table. Can you slipstream these new indexes and constraints during normal business hours or will you have to schedule the creation of these indexes for a time when usage is relatively light?
You don't make clear what benefit there is in having the data from separate universes mingled in the same table.
Uniqueness constraints are part of the entity definition and each entity needs its own table. I'd create separate tables.

How to insert two rows in one column with same id, different cultureId and in different Languages?

I have a table Culture, Companies and CompaniesLocale. In Culture table i have CultureId, CultureCode and DisplayName , in Companies i have CompanyID, Name and in CompaniesLocale I have CompanyID, CultureId, Name. I inserted to languages in culture table English and German.
Now When i create a new company how i am going to insert into CompaniesLocale the same Name that is created in Companies but as described in different language(I Choose German but i can be maybe a Cyrillic. I want the new company to be added first to Companies then in CompaniesLocale with the same COmpanyId but the proper CultureId for the language.
Is that possible?
something like
insert into CompanyLocal(CompanyId, CultureId, Name) values (1, 1, 'spreken zie deutch')
Basically, I can see two approaches.
Two inserts. First insert a record with the base locale name into Company, get the new CompanyID, then insert the rest of the names into CompanyLocale using the obtained CompanyID. This assumes there's a trigger ON Company FOR INSERT which adds the base locale name to CompanyLocale.
One insert. Insert all the names into CompanyLocale with empty CompanyID values. This also assumes using a trigger, this time it's ON CompanyLocale FOR INSERT. The trigger inserts a new record into Company, gets the new id and updates it for the newly inserted CompanyLocale records. Also this assumes that the foreign key column CompanyLocale.CompanyID, which references Company.ID, must allow NULL values. (With the first approach I think it can be prohibited from getting NULLs.)

SQL Server 2005 T-SQL remap columns

I have an application that is ready to go live, once we take data from a MS Access DB and import it into SQL Server 2005. I have used the Migration - Access tool to get the Access db into SQL Server, but now I need to take the data from that table and put it into the tables that our app is going to use. Is there a T-Sql way to Insert multiple rows, while at the same time 're-mapping' the data?
For example
SELECT ID, FIRST_NAME, LAST_NAME
INTO prod_users (user_id, first_name, last_name)
FROM test_users
I know that select * into works when the column names are the same, but the
prod_users (column names, ..., ...)
part is what I really need to get to work.
Any ideas?
I believe the SELECT INTO syntax is used to create new tables. If you want to map data from the tables you just imported to some other existing tables, try a plain INSERT. For example:
INSERT INTO prod_users (user_id, first_name, last_name)
SELECT ID, FIRST_NAME, LAST_NAME
FROM test_users
The mapping of columns from test_users to prod_users is based on the order that they are listed, i.e. the first column in "prod_users (column_names, ...)" matches the first column in the "SELECT other_col_names, ...", the second matches the second, etc. Therefore, in the code sample above, ID is mapped to user_id, and LAST_NAME is mapped to last_name, and so on.
Just make sure you have the same number of columns in each list and that the column types match (or can be converted to match). Note that you don't have to specify all the columns in either table (as long as the destination table has valid defaults for the unspecified columns).
See the INSERT syntax for details; the part relevant to your question is the "execute_statement" expression.
INSERT and SELECT are the magic keywords:
insert into new_table (list of columns) select columnA, functionB(),
(correlated_subquery_C) from table_or_join where critera_expression_is_true
Maybe you can be more specific about what you mean by re-mapping?
Base on your comment, a more specific query is:
insert into new_table (user_id, firstname, lastname)
select id, first_name, last_name from old_database..old_table

iSeries DB2 - Is there any way to select the identity value from an insert statement?

I know we're rare, us poor folk that are using iSeries for DB2/AS400, but I'm hoping someone can answer this simple question. Is there any way to return the identity value from an insert statement without using two lines of SQL? I'm being forced to use inline SQL in C# to perform an insert, and then I need to use the identity generated for the insert for something later on. Simply put, I need the iSeries DB2 equivalent of Oracle's "RETURNING." I.e.,
INSERT INTO AwesomeTable (column1, column2, etc.)
VALUES (value1, value2, etc.)
RETURNING something;
Anyone? Thanks in advance.
EDIT: Unless someone knows of a way I can execute two lines of SQL in one IBM.Data.DB2.iSeries.iDB2Command (not a stored proc), I would like to do this all in one line of SQL
I am not sure of iSeries, but the following worked on db2v8.1:
Consider 'ID' is the name of your identity column. The following stmt will return the newly generated id (the same one that gets inserted by the insert stmt):
SELECT ID FROM FINAL TABLE (
INSERT INTO AwesomeTable (column1, column2, etc.)
VALUES (value1, value2, etc.)
)
Some explanation I found on the publib site: (I used it for reference to test my query above)
/* The following SELECT statement references an INSERT statement in its
FROM clause. It inserts an employee record from host variables into
table company_b. The current employee ID from the cursor is selected
into the host variable new_id. The keywords FROM FINAL TABLE
determine that the value in new_id is the value of ID after the
INSERT statement is complete.
Note that the ID column in table company_b is generated and without
the SELECT statement an additional query would have to be made in
order to retreive the employee's ID number.
*/
EXEC SQL SELECT ID INTO :new_id
FROM FINAL TABLE(INSERT INTO company_b
VALUES(default, :name, :department, :job, :years, :salary,
:benefits, :id));
Hope this helps :)
You need to use the IDENTITY_VAL_LOCAL scalar function. From the IBM documentation:
IDENTITY_VAL_LOCAL is a
non-deterministic function that
returns the most recently assigned
value for an identity column.
Example:
CREATE TABLE EMPLOYEE
(EMPNO INTEGER GENERATED ALWAYS AS IDENTITY,
NAME CHAR(30),
SALARY DECIMAL(5,2),
DEPT SMALLINT)
INSERT INTO EMPLOYEE
(NAME, SALARY, DEPTNO)
VALUES('Rupert', 989.99, 50)
SELECT IDENTITY_VAL_LOCAL() FROM SYSIBM.SYSDUMMY1
Here's an example :
CREATE TABLE AUTOINC (
AUTO91 INTEGER GENERATED ALWAYS AS IDENTITY,
SCDS91 CHAR(35) NOT NULL DEFAULT '',
MCLD91 DECIMAL(3,0) NOT NULL DEFAULT 0,
CONSTRAINT PK_AUTOINC PRIMARY KEY(AUTO91));
// Notice the default keyword where the auto increment field is.
insert into AUTOINC Values( default ,'SYSC' , 0 )
// And using the function to return the last identity column value.
// Note: fetch first row only.
select **IDENTITY_VAL_LOCAL**() from AUTOINC **fetch first row only**