Split a row in a table into multiple rows from CSV - sql

How do I split a row into multiple rows with SQL?
I have a .csv file that I've imported into a table in MS Azure Data Studio, and SQL Server Management Studio (trying both). It is a table of invoices with a header ("H") and details ("D").
I need to split each row within the table into multiple rows at a specific delimiter or column number.
I have a table that looks like this:
I need a table that looks like this, where each row is split at Column 8, and the data from the split row is inserted under the initial data.
Here is how to create the table:
CREATE TABLE InvoicesDemo2
(
[Column1] [nvarchar](1) NULL,
[Column2] [nvarchar](50) NULL,
[Column3] [nvarchar](50) NULL,
[Column4] [date] NULL,
[Column5] [date] NULL,
[Column6] [nvarchar](1) NULL,
[Column7] [money] NULL,
[Column8] [nvarchar](50) NULL,
[Column9] [nvarchar](50) NULL,
[Column10] [money] NULL
)
INSERT INTO InvoicesDemo2
VALUES ('H', 'VEN000002286', '27483387', '2023-02-14', '2023-02-14', NULL, 1840.60, 'D', '2501', 1840.60)
INSERT INTO InvoicesDemo2
VALUES ('H', 'VEN000002286', '27480005', '2023-02-13', '2023-02-13', NULL, 243.39, 'D', '2501', 243.39)
INSERT INTO InvoicesDemo2
VALUES ('H', 'VEN000002286', '27480003', '2023-02-13', '2023-02-13', NULL, 1601.64, 'D', '2501', 1601.64)
Thank you!

For getting match your desired format output you can try this query:
Note: This query is based on your given data and expected output.
SELECT Column1, Column2, Column3, Column4, Column5, Column6, Column7
FROM InvoicesDemo2
WHERE Column1 = 'H'
UNION ALL
SELECT 'D' as Column1,
Column9 as Column2,
Column10 as Column3,
NULL as Column4,
NULL as Column5,
NULL as Column6,
NULL as Column7
FROM InvoicesDemo2
WHERE Column1 = 'H'
ORDER BY Column2, Column1;

You need to union all, ordering by row number and row type e.g.
with cte as (
select Column1, Column2, Column3, Column4, Column5, Column6, Column7
, row_number () over (order by Column2, Column3) RowNumber,
, 0 RowOrder
from MyTable
union all
select Column8, Column9, Column10, null, null, null, null
, row_number () over (order by Column2, Column3) RowNumber
, 1 RowOrder
from MyTable
)
select Column1, Column2, Column3, Column4, Column5, Column6, Column7
from cte
order by RowNumber asc, RowOrder asc;
Note: I am assuming that order by Column2, Column3 gives the correct, unique, order of the rows.

This is just dreadfully awful and something that really should not be done this way. I would really work hard to find a solution to fix the source data so isn't so absurd. But sometimes that just isn't possible.
Here is one way to deal with this. First I added a ROW_NUMBER so we can number each row from the original data. We need that in order for the final sort. This works with the sample data that you posted. I would be careful here as the datatypes seem to be a little suspect. And I would avoid using the money datatype if at all possible.
with MergedData as
(
select h.Column1
, h.Column2
, h.Column3
, h.Column4
, h.Column5
, h.Column6
, h.Column7
, RowNum = ROW_NUMBER() over(order by Column1)
from InvoicesDemo2 h
union all
select d.Column8
, d.Column9
, d.Column10
, null
, null
, null
, null
, RowNum = ROW_NUMBER() over(order by Column1)
from InvoicesDemo2 d
)
select md.Column1
, md.Column2
, md.Column3
, md.Column4
, md.Column5
, md.Column6
, md.Column7
from MergedData md
order by md.RowNum
, md.Column1 desc

So, you’re going to get a lot of questions.
The main one being - why would anybody want to do this like this?
I’m having a hard time thinking up a scenario where anyone would want to start with your input and end up with your output.
Your data types for column 3 and column 10 are mismatched, which may add another wrinkle for you.
But try this - edited to account for good ideas from Dale K.
WITH LiamsCte
As (
Select
ROW_NUMBER() OVER (Order By Column2) as MyRowNumber,
Column1,
Column2,
Column3,
Column4,
Column5,
Column6,
Column7,
Column8,
Column9,
Column10
)
Select column1, column2, column3, column4, column5, column6, column7
From LiamsCte
Order by MyRowNumber
Union All
Select column8, column9, column10, null, null, null, null
From LiamsCte
Order by MyRowNumber
It may throw you an error about data types in which case you need to google how to convert column3 (the one that is a money data type) to nvarchar(50).

Related

Is is possible to use a CTE combined with a UDT to delete data?

I have a stored procedure that takes in a UDT. I would like to sanitize this data before inserting into the database to prevent any duplicate data from getting inserted. (Primary Key is still allowing duplicate data just the PK is different).
So I am using shorthand with a cte to get remove all of the possible duplicate rows and then use the clean data to insert into my table
The problem is I am getting an error that "#UDT_MyTable is READONLY and cannot be modified". Is there someway around this without going the temp table route?
Create Procedure InsertIntoMyTable
(
#UDT_MyTable dbo.MyUDT readonly
)
as
Begin
declare #TodaysDate datetime = CURRENT_TIMESTAMP
begin transaction
;with cte as
(
Select Row_Number() Over
(
PARTITION BY
Column1,
Column2,
Column3,
Column4,
Column5,
Column6
)
as sequence from
#UDT_MyTable
Errors Here
**Delete from cte Where sequence > 1**
insert into my table(
Column1,
Column2,
Column3,
Column4,
Column5,
Column6,
DateCreated
)
select
Column1,
Column2,
Column3,
Column4,
Column5,
Column6,
#TodaysDate
from cte

MS SQL output inserted with insert from select

I'm trying to figure out how to combine INSERT FROM SELECT and returning id value of inserted record.
INSERT INTO [someDB].[dbo].[OBJ] ( column1, column2, column3 )
OUTPUT inserted.ID (SELECT TOP 1 590675, column2, column3
FROM [someDB].[dbo].[OBJ] WHERE ID = 317817)
If you are trying to get the new ID after your INSERT statement you can use SCOPE_IDENTITY, IDENT_CURRENT or ##IDENTITY. For example:
INSERT INTO [someDB].[dbo].[OBJ] ( column1, column2, column3 )
SELECT TOP 1
590675,
column2,
column3
FROM [someDB].[dbo].[OBJ] WHERE ID = 317817
ORDER BY ...
SELECT SCOPE_IDENTITY(); -- Last identity generated in current session and current scope
SELECT ##IDENTITY; -- Last identity generated in current session across all scopes
SELECT IDENT_CURRENT([someDB].[dbo].[OBJ]) -- Last identity generated for the given table in any session and any scope
Because you are inserting just one row, SCOPE_IDENTIY() would be the best approach.
Hope it helps.
Your syntax is a little wrong here.
You want:
INSERT INTO [someDB].[dbo].[OBJ] ( column1, column2, column3 )
OUTPUT inserted.ID
SELECT TOP 1
590675,
column2,
column3
FROM [someDB].[dbo].[OBJ] WHERE ID = 317817
ORDER BY ...?; --You have a TOP 1, thus you really need an ORDER BY as well.

Append columns to a table by selecting columns from another table

Alter Table table2 add ( select column1, column2, column3, column4 from table1 );
I need to append columns in an existing table, by selecting the columns of another table.
I get Error! Looking forward for a possible solution
First, to add four new columns to the table use the following syntax:
ALTER TABLE Table2
ADD column1 <datatype> <allow null>,
column2 <datatype> <allow null>,
column3 <datatype> <allow null>,
column4 <datatype> <allow null>
Where <datatype> is the type of data you'll be adding to the column and <allow null> is NULL if you want to allow null values is the column and NOT NULL if you do not want to allow null values in the column.
For example to add four columns of type nchar with a size of 10 that allow null values you would do the following:
ALTER TABLE Table2
ADD column1 [nchar](10) NULL,
column2 [nchar](10) NULL,
column3 [nchar](10) NULL,
column4 [nchar](10) NULL
Next, to insert your data from table1 into this table as brand new record you would use the following sql:
insert into table2 (column1, column2, column3, column4)
select column1, column2, column3, column4
from table1
Note: if any of the original columns in your table are set to NOT NULL and do not have have a default value this will fail and you will have to set values for those columns as well. You would do that by using a command similar to where you set a specific value for the column not allowing NULL values:
insert into table2 ( existingColumn, column1, column2, column3, column4)
select 'value to insert', column1, column2, column3, column4
from table1

INSERT INTO subtract 2 values

Is it possible for an INSERT query to subtract 2 values you have entered to create a 3rd value that can then be inserted into a table - if that makes sense...
e.g.
INSERT INTO table1 (column1, column2, column3)
VALUES ('50', '25', column1 - column2)
INSERT INTO table1 (column1, column2, column3)
(select ('50', '25', column1 - column2) from table1 where conditions)
This is a sample query! hope it helps!
Convoluted:
INSERT INTO table1 (column1,column2,column3)
select column1,column2,column1-column2
from
(select 50 as column1,
25 as column2
) t
Since you can't reference other columns from the same SELECT clause, you have to do it as a subquery. I've also switched to using int literals rather than strings, because I can't make subtraction make sense in my head otherwise.
You could also do it using a Table Value Constructor:
INSERT INTO table1 (column1,column2,column3)
select column1,column2,column1-column2
from
( VALUES (50, 25)
) AS t (column1, column2);
As indicated in my comment though, if the relationship should always hold, I'd build table1 as:
CREATE TABLE table1 (
column1 int not null,
column2 int not null,
column3 as column1 - column2
--More columns
)
Because that way, the column3 value is always correct.
You can create function that subtracts values and use this function in insert. This is the right way to do such things:
INSERT INTO table1 (column1, column2, column3)
(select ('50', '25', your_function() ) from table1 where conditions)
/
Using the "INSERT INTO" would do this:
INSERT INTO Table1Name (column1, column2, column3,)
(select 'X', 'Y', X - Y as Z)
Here is a link to SQL Authority with more examples of INSERT INTO
Another method would to be add a trigger to the table, where on insert of data, the third column would be updated with the difference of the first two columns.

Populating temporary table with result of independent Sql Query

I want to return a temporary table from stored procedure which populates with data retrieved from two independent sql query
Select column1,column2 FROM TABLE1 WHERE someCondition
Select column3,column4 FROM TABLE1 WHERE someOtherCondition
INSERT INTO Temp_table(column1,column2,column3,column4) values VALUE from those two table
Some of the result from table contains null as well.Also i am using some mathematical function like sum on some column as well
Thanks in advance
Try out with following code:
INSERT INTO Temp_table (column1, column2, column3, column4)
SELECT column1, column2, ISNULL(column3,0), ISNULL(column4,0) FROM TABLE1 WHERE someCondition
UNION ALL
SELECT ISNULL(column1,0), ISNULL(column2,0), column3, column4 FROM TABLE1 WHERE someOtherCondition
You want to do something like:
INSERT INTO Temp_table (column1, column2, column3, column4)
SELECT column1, column2, NULL AS column3, NULL AS column4 FROM TABLE1 WHERE someCondition
UNION
SELECT NULL AS column1, NULL AS column2, column3, column4 FROM TABLE1 WHERE someOtherCondition