SQL Pivot table - sql

Is there a way to pivot an Entity-Attribute table?
I want to flip all the rows into columns, regardless of how many different attributes there are.
Here's an example of what I want to accomplish. The example uses two attributes: FirstName, LastName. But in the real database, there are thousands of attributes and I want to flip them into columns for reporting purposes.
I don't want to have to write a CTE for every attribute.
USE TempDB
DECLARE #Attribute TABLE(
AttributeID Int Identity(10,1) PRIMARY KEY,
AttributeName Varchar(MAX))
INSERT INTO #Attribute(AttributeName) VALUES('Firstname')
INSERT INTO #Attribute(AttributeName) VALUES('Lastname')
DECLARE #tbl TABLE(
AttributeID Int,
EntityValue Varchar(MAX)
)
INSERT INTO #tbl(AttributeID,EntityValue) VALUES(10,'John')
INSERT INTO #tbl(AttributeID,EntityValue) VALUES(10,'Paul')
INSERT INTO #tbl(AttributeID,EntityValue) VALUES(10,'George')
INSERT INTO #tbl(AttributeID,EntityValue) VALUES(10,'Ringo')
INSERT INTO #tbl(AttributeID,EntityValue) VALUES(11,'Lennon')
INSERT INTO #tbl(AttributeID,EntityValue) VALUES(11,'McCartney')
INSERT INTO #tbl(AttributeID,EntityValue) VALUES(11,'Harrison')
SELECT A.AttributeID,AttributeName,EntityValue FROM #tbl T
INNER JOIN #Attribute A
ON T.AttributeID=A.AttributeID
DECLARE #Tbl2 Table(
FirstName Varchar(MAX),
LastName Varchar(MAX)
)
INSERT INTO #Tbl2(FirstName,LastName) VALUES('John','Lennon')
INSERT INTO #Tbl2(FirstName,LastName) VALUES('Paul','McCartney')
INSERT INTO #Tbl2(FirstName,LastName) VALUES('George','Harrison')
INSERT INTO #Tbl2(FirstName) VALUES('Ringo')
SELECT * FROM #Tbl2

Based on what you posted, you're dealing with SQL Server.
The old school method is to use IF or CASE statements to represent each column you want to create. IE:
CASE WHEN t.AttributeID = 10 THEN t.EntityValue ELSE NULL END 'FirstName'
The alternative is to use PIVOT (SQL Server 2005+).
In either case, you're going to have to define the output columns by hand. If you model was setup to address it, you might be able to use dynamic SQL.

In case you're curious, the reason Microsoft SQL Server's PIVOT operator isn't "dynamic," and that you must specify each value to pivot, is that this makes it possible to identify the table structure of the PIVOT query from the query text alone. That's an important principle of most programming languages - it should be possible to determine the type of an expression from the expression. The type shouldn't depend on the run-time values of anything mentioned in the expression.
That said, some implementations of SQL implement what you want. For example, I think Microsoft Access does this with TRANSFORM.
If you search the web for "dynamic pivot", you'll find a lot.

Related

Compare data between two tables with in single database

My requirement to compare two table data with in one database and stored the uncommon data in separate table named relation data within same database.
How to compare this tables data?
To compare is their any tools and can we stored uncommon data in separately table using any tool?
i forgot to tell one thing that two tables having same data but different column names that means for example first table having 20 columns and 2 and table having 50 columns but in that 4 columns are matched data with different number of rows and different column names in each table.based on these columns data matching i need to find rows and stored into another table
As an alternative to writing a SQL script, you could copy the entire results from both tables to a .csv file and then use win merge to compare the two:
http://winmerge.org/downloads/
I have used this technique in the past when comparing mass amounts of data and it has worked quite well.
This can be accomplished in t-sql with not a lot of effort. However in your question you were asking for a tool to accomplish this. If you are simply looking to purchase a tool to do this, at my job, we use the Redgate tools for deploying code from test to production, and I believe if you were a little creative you could get the SQL Data Compare Tool to do what you are asking for.
If you select and compare these two tables, it will generate a change script from one to the other. If you only take the changes from one, save off the script, then come back, click on the arrow and take only the changes from the source the other way, you should have the uncommon attributes.
Try this query, I think its work
insert into relational(r1,r2,r3,....rn)
(select s1,s2,s3,...sn from
information info where info.informationcity not in (select customercity from customer)
and info.informationstate not in (select customerstate from customer) )
Assuming you both tables have the same structure
Quick and dirty?
;WITH cte AS (
SELECT 1 AS OriginTable, *
FROM OriginTable1
UNION SELECT 2 AS OriginTable, *
FROM OriginTable2
)
SELECT {put here the list of all your columns}
INTO [YourDeltaTable]
FROM cte
GROUP BY {put here the list of all your columns}
HAVING COUNT(*) = 1
You can use the following query for inserting data into target table by retrieving data from multiple tables
insert into TargetTable(list_of_columns)
(select list of columns from
Table1 t1 join Table2 t2
on (t1.common_column != t2.common_column))
The src column list count and target column list count should be equal
Here's a simple example that assumes your table structures are the same
DECLARE #a table (
val char(1)
);
DECLARE #b table (
val char(1)
);
INSERT INTO #a (val)
VALUES ('A'), ('B'), ('C');
INSERT INTO #b (val)
VALUES ('B'), ('C'), ('D'), ('E');
DECLARE #mismatches table (
val char(1)
);
INSERT INTO #mismatches (val)
SELECT val -- All those from #a
FROM #a
EXCEPT -- Where not in #b
SELECT val
FROM #b;
INSERT INTO #mismatches (val)
SELECT val -- All those from #a
FROM #b
EXCEPT -- Where not in #b
SELECT val
FROM #a;
SELECT *
FROM #mismatches

Fixing SQL Update using XQuery modify to work on SQL 2005

I'm trying to move a bunch of fields from a table into an xml blob contained within the same table. After this is successful I will be removing the column from the table. A really simple version (without the drop column) of what I've come up with is below, and this works fine on SQL 2008 - however I've discovered that this will not work on SQL 2005. I get the error XQuery: SQL type 'datetime' is not supported in XQuery. I'm actually doing this through the execution of a constructed SQL statement within a SP because of the number of fields, but for simplicity I've used a normal statement in the example:
if OBJECT_ID('tempdb..#Case') is not null
DROP Table #Case;
CREATE TABLE #Case
(
id INT,
DecisionDate DateTime,
CaseBlob xml
)
INSERT INTO #Case Values(1, '10-OCT-2011 10:10:00', '<CaseBlob></CaseBlob>')
INSERT INTO #Case Values(2, '20-OCT-2011 10:10:00', '<CaseBlob></CaseBlob>')
INSERT INTO #Case Values(3, null, '<CaseBlob></CaseBlob>')
INSERT INTO #Case Values(4, '21-OCT-2011 10:10:00', '<CaseBlob></CaseBlob>')
INSERT INTO #Case Values(5, null, '<CaseBlob></CaseBlob>')
UPDATE #Case
SET CaseBlob.modify('insert <DecisionDate>{sql:column("#Case.DecisionDate")}</DecisionDate>
as last into (/CaseBlob)[1]')
WHERE #Case.DecisionDate is not null
AND CaseBlob.exist('(/CaseBlob/DecisionDate)') = 0
SELECT * FROM #CASE
I've tried wrapping the sql:column("#Case.DecisionDate") with xs:string(sql:column("#Case.DecisionDate")) but that doesn't seem to help. It has been pointed out by #marc_s that the use of sql:column( within a .modify(insert statement wasn't introduced until SQL 2008 - so I think this is a red herring.
Due to the fact this is a one off migration script and only requires to be run once, am I thinking that I should move away from the Set methods and move to a procedural looping method to cater for my requirements. Does this sound like the correct approach due to the limitation of server version and what I'm trying to achieve? Any pointers greatly appreciated.
First part:
You can use a CTE to query the date part converted to a string using the date time style 126.
;with C as
(
select CaseBlob,
convert(varchar(23), DecisionDate, 126) as DecisionDate
from #Case
where DecisionDate is not null and
CaseBlob.exist('(/CaseBlob/DecisionDate)') = 0
)
update C
set CaseBlob.modify('insert <DecisionDate>{sql:column("DecisionDate")}</DecisionDate>
as last into (/CaseBlob)[1]')
There is a tiny difference in the output using this compared to your update statement. It will omit the milliseconds if they are .000. If they actually have a value it will be included so you are not missing any data. It's just different.
Second part:
I don't really understand how this connects to the above well enough to give you some sample code. But if you need to add more stuff from other tables you can join to those tables in the CTE and make the columns as output from the CTE to be used in the modify statement inserting values.

what is the difference between insert statement with into and without into?

I have created table #temp with columns id as int identity(1,1) and name as varchar.
Say suppose I am writing the following 2 different statements for inserting rows:
insert into #temp (name) select ('Vikrant') ;
insert #temp (name) select ('Vikrant')
I want to ask what is the difference between these two types of insert statements?
Is there really any difference in between these insertions?
From the MSDN documentation:
[INTO]
Is an optional keyword that can be used between INSERT and the target table.
There is no difference between the two statements.

SQL Server and Table-Valued User-Defined Function optimizations

If I have an UDF that returns a table, with thousands of rows, but I just want a particular row from that rowset, will SQL Server be able to handle this effciently?
DECLARE #pID int; --...
SELECT * FROM dbo.MyTableUDF(#pID)
WHERE SomeColumn BETWEEN 1 AND 2 OR SomeOtherColumn LIKE 'this_pattern&'
To what extent is the query optimizer capable of reasoning about this type of query?
How are Table-Valued UDFs different from traidtional views if they take no parameters?
Any gotchas I should know about?
Wouldn't you pass in the ID that you require as a parameter rather query the entire table?
Something like this:
CREATE FUNCTION dbo.MyTableUDF(#ID int)
RETURNS #myTable TABLE
(
ID int PRIMARY KEY NOT NULL,
FirstName nvarchar(50) NULL,
LastName nvarchar(50) NULL
)
as begin
Insert Into #myTable (ID, FirstName, LastName)
Select ID, FirstName, LastName
From Users
Where ID = #ID
return
end
go
Select * From MyTableUDF(1)
For this scenario, it would be a far better approach.
EDIT:
Ok well as you're using a Table UDF rather than a view I will assume that it a multi statement table UDF rather than an inline. I am pretty sure that the performance won't be affected by using the UDF in this way.
The performance will really be hit if you used the UDF in a Select statement or Where clause. This is because the UDF will be called for each row returned from the table.
e.g Select col1, col2, dbo.MyUDF(col3) From MyTable
or
Select col1, col2 from dbo.MyTable Where dbo.MyUDF(col3) != 1
So if you MyTable contained 100,000 rows, your UDF will be called 100,000 times. If the UDF takes 5 seconds to execute that is where you will run in to issues.
As far as I can make out you don't intend on using the UDF in this manner.

Asking a Microsoft SQL Server database for the next auto-generated identifier on a table

I have a table in a SQL Server database that has an auto-generated integer primary key. Without inserting a record into the table, I need to query the database and get what the next auto-generated ID number will be.
I think it's SQL Server version 2005, if that makes a difference.
Is there a way to do this?
Yes, but it's unreliable because another session might use the expected number.
If you still want to do this, use IDENT_CURRENT
Edit, as the comments have pointed out (improving my answer):
you need to add one IDENT_INCR('MyTable') to this to get the potential next number
another process may rollback and this number may not be the one used anyway
No, there is not. The ID will only ever be defined and handed out when the actual INSERT happens.
You can check the last given ID by using
DBCC CHECKIDENT('YourTableName')
but that's just the last one used - no guarantee that the next one is really going to be this value + 1 - it could be - but no guarantees
The only way to get a number that is guranteed not to be used by another process (i.e., a race condition) is to do the insert - is there any reason you can't do a NULL insert (i.e., just insert into the table with NULLs or default values for all other columns) and then subsequently UPDATE it?
i.e.,
CREATE TABLE bob (
seq INTEGER IDENTITY (1,1) NOT NULL,
col1 INTEGER NULL
)
GO
DECLARE #seqid INTEGER
INSERT INTO bob DEFAULT VALUES
SET #seqid = SCOPE_IDENTITY()
-- do stuff with #seqid
UPDATE bob SET col1 = 42 WHERE seq = #seqid
GO
You shouldn't use the technique in code, but if you need to do it for investigative purposes:
select ident_current(‘foo’) + ident_incr(‘foo’)
That gives you the last value generated + the incrementation for the identity, so should represent the next choice SQL would make without inserting a row to find out. This is a correct value even if a rollback has pushed the value forwards - but again, this is investigative SQL not stuff I would put in code.
The two values can also be found in the sys.identity_values DMV, the fields are increment_value and last_value.
Another way, depending on what your doing, is inserting whatever data goes into the table, and then using ##identity to retrieve the id of the record inserted.
example:
declare #table table (id int identity(1,1), name nvarchar(10))
insert into #table values ('a')
insert into #table values ('b')
insert into #table values ('c')
insert into #table values ('d')
select ##identity
insert into #table values ('e')
insert into #table values ('f')
select ##identity
This is pretty much a bad idea straight off the bat, but if you don't anticipate high volume and/or concurrency issues, you could just do something like this
select #nextnum = max(Id) + 1 from MyTable
I don't think thats possible out of the box in MS SQL (any version). You can do this with column type uniqueidentifier and using function NEWID().
For int column, you would have to implement your own sequential generator.