In Excel how to create multiple rows from a single data row - sql

I have an execl datasheet with data looking like this
id desc part no 1 Qty 1 part no 2 Qty 2 part no 3 Qty 3
1 PartsName 382A012-3-0 3 382A023-3 3 382A012-25 3
And need it to look like this
id desc part no Qty
1 PartsName 382A012-3-0 3
1 PartsName 382A023-3/42-0 3
1 PartsName 382A012-25/86-0 3
This from a SQL Table so I could do it in SQL if that makes it easier
Anybody any suggestions as how to best to sort this?

Simply make a UNION in the SQL
SELECT id, desc, partNo, qty FROM parts
UNION SELECT id, desc, partNo2 as partNo, qty2 as qty FROM parts
UNION SELECT id, desc, partNo3 as partNo, qty3 as qty FROM parts
ORDER BY id

If you don´t have the option of using SQL and need to use Excel. You can use the TRANSPOSE function. It is an array type function so you need to use the {}. If you haven´t used it before I recommend reading the help first. I however don´t think you can use transpose to get it exactly as you describe it. The id and desc column have to handled separately.

You need to add next formulas on a new sheet:
column A=MOD(ROW()+1,3)
it's like a skeleton :)
First row is headers
column B
=IF($A2=0,OFFSET(Sheet1!$A$1,COUNTIF($A$2:$A2,0),COLUMN()-2),B1)
autofil col C with it
column D
=OFFSET(Sheet1!$A$1,COUNTIF($A$2:$A2,0),COLUMN()+CHOOSE($A2+1,-2,0,2))
autofil col E with it
one more - your datasheet is "sheet1"

Related

How to classify rows having one or more related records

I need to add the additional column called rank_2 which will show whether the source has more than 1 source_ids.
So, I need to get this result:
I don't know how to write a query to get rank_2, which will contain 1 when the source has the only source_id (like the source "b") and contain 2 when the source has 2 or more source_ids (like the source "a").
Assuming window functions are available you can use a query like so:
select *
, case when count(*) over (partition by date, source_name) = 1 then 1 else 2 end as rank_2
from t
With the count function you will be able to resolve this problem:
, count(source_id) as rank_2
Don't forget to group by date, source_name, source_id.
I only don't understand why source_id 11 needs to get value 1 as it is also shown two times in the table.

SQL: Select, dynamically created values as column

I have to select data from a column then show as these values as another columns. But the struggle is, inside my column always new data will come and new cells will be created.
Product_Table:
ID NAME
1 apple
2 orange
Selling_Table:
ID PRODUCT_ID DATE
1 1 2020-06-12
2 1 2020-05-03
3 2 2020-01-01
4 1 2020-07-23
What I Want
NAME SELLING_DATE_1 SELLING_DATE_2 SELLING_DATE_3
APPLE 2020-06-12 2020-05-03 2020-07-23
ORANGE 2020-01-01 NULL NULL
When there is a new date in selling table I want my SQL create another SELLING_DATE dynamically. As you notice when there is no SELLING_DATE data filled with null or we can replace basic text like 'not sold'
You can use window functions and conditional aggregation:
select
name,
max(case when rn = 1 then date end) selling_date_1,
max(case when rn = 2 then date end) selling_date_2,
max(case when rn = 3 then date end) selling_date_3
from (
select p.*, s.date, row_number() over(partition by p.id order by s.date) rn
from product_table p
inner join selling_table s on s.product_id = p.id
) t
group by id, name
You can expand the query with more columns (that is, more conditional max()s) to handle more dates.
I really don't think it's practical to solve your problem that way.
A couple of things you could try instead:
Just select each product once per sale, i.e. join them, which in practice is almost the same as replacing the ID's in your selling_table with the names of the products. That should give you something like:
PRODUCT SELLING DATE
apple 2020-06-12
apple 2020-05-12
apple 2020-07-23
orange 2020-01-01
You can try selecting all dates for each product together and display them as a string (may require some research and work though if you're new to SQL). This answer do a somewhat similar question may perhas help you.
Perhaps you are calling this from some higher level program? If you are using C# for instance, you could probably manipulate whatever result you get pretty easily using e.g. LINQ. That all depends on what the bigger picture looks like though, and how you want to present your final result.
To that end, it would be useful if you could update your question with more info about your overall architecture.

SQL - Query to split original sort

I hope my title is ok as I really don’t know how to call it.
Anyway, I have a table with the following :
ID - Num (Primary Key)
Category - VarChar
Name - VarChar
DateForName - Date
Data looks like that :
1 100 111 31/12/2017
2 101 210 30/12/2017
3 100 112 29/12/2017
4 101 203 27/12/2017
5 100 117 20/12/2017
6 103 425 08/12/2017
To generate this table, I just sorted by date DESC.
Is there a way to add a new column with the order per Category like :
1 100|1
2 101|1
3 100|2
4 101|2
5 100|3
6 103|1
Max
You want analytical function row_number():
select t.*
from (select *, row_number() over (partition by Category order by date desc) Seq
from table
) t
order by id;
Yes, SQL has a couple options for you to add a column that is populated with a ranking of the rows based on the category and id columns.
If you just want to add a column to the select statement, I recommend using the RANK() function.
See more details here:
https://learn.microsoft.com/en-us/sql/t-sql/functions/rank-transact-sql?view=sql-server-2017
For your current table, try the following select statement:
SELECT
[ID],
[Category],
[Name],
[DateForName],
RANK() OVER (PARTITION BY [Category] ORDER BY [DateForName] DESC) AS [CategoryOrder]
FROM [TableName]
Alternatively, if you want to add a permanent column (aka a field) to the existing table, I recommend treating this as a calculated column. See more information here:
https://learn.microsoft.com/en-us/sql/relational-databases/tables/specify-computed-columns-in-a-table?view=sql-server-2017
Because the new column would be completely based on two pre-existing columns and only those two columns. SQL can do a great job maintaining this for you.
Hope this helps!

SQL - Possible to sum rows between particular values?

my apologies if this is a duplicate but I could not find an answer to my particular question. I have a table that lists products on a sales order, and their various quantities. Some products are components for other products and are denoted so with a flag. I would like to know if there is a way to have a running total for the parent/normal items that would reset on each parent/normal item.
Here is an example of the table data and my desired output:
OrderNo Item Qty Regular Line
349443 AFU20451-KIT1 1 Y 1
349443 AFU20451 0 N 2
349443 HAWKE-14252 1 N 3
349443 RGPM-25H4 1 N 4
349443 AV-003-265 1 Y 5
349443 AV-A00090-KIT 1 Y 6
349443 AV-A00091 1 N 7
349443 AV-A00090 1 N 8
349443 AV-00043 1 N 9
349443 AV457/310GR/FP 2 Y 10
desired output:
OrderNo Item Qty
349433 AFU20451-KIT1 3
349433 AV-003-265 1
349433 AV-A00090-KIT 4
349433 AV457/310GR/FP 2
As you can see, I would like to reset the sum every time it says Y, only include the parent item (I could get around this as I can keep the order of the items the same, could maybe use row number). I have been trying to use Over and Partition by in order to do this, but to no avail. Let me know if this is even possible or if you need any further information.
with cte as
(
select OrderNo,
-- only return the main item
case when Regular = 'Y' then Item end AS Item,
Qty,
-- assign a unique number to each `YNNN..` component group
-- needed for GROUP BY in next step
sum(case when Regular = 'Y' then 1 else 0 end)
over (partition by OrderNo
order by Line
rows unbounded preceding) as grp
from myTable
)
select OrderNo,
-- find the matching value for the main component
max(Item),
sum(Qty)
from cte
group by OrderNo, grp
Current representation is against 1st Codd's rule.
Rule 1: The information rule: All information in a relational data
base is represented explicitly at the logical level and in exactly one
way – by values in tables.
But I believe you can still create FUNCTION/PROCEDURE and iterate row one by one with IF statement for Y/N. E.g. you create new table, IF Y - add new row to table, IF N - add +1 to QTY to latest row.
I would create two separate tables: manufacturer & part, to get the values so you don't have to hand-jam each inventory, or care about where they fall in the invoice list.
[1
[]2
Then, all you would need to do is compare the values to the part table to get this data. It's more work upfront, but will pay off to have this all saved and stored. A future sample query would look something like:
SELECT OrderNo.OrderTable, Item.OrderTable, Sum(Qty.OrderTable) AS Quantity
FROM OrderTable INNER JOIN Part ON OrderTable.Item = Table.PartName
GROUP BY OrderNo.OrderTable, Item.OrderTable, Regular.OrderTable, Part.ParentID;
try this:
select orderno, item, sum(qty) over(partition by regular order by regular)
from your_table
group by orderno, item, regular

Select query to fetch required data from SQL table

I have some data like this as shown below:
Acc_Id || Row_No
1 1
2 1
2 2
2 3
3 1
3 2
3 3
3 4
and I need a query to get the results as shown below:
Acc_Id || Row_No
1 1
2 3
3 4
Please consider that I'm a beginner in SQL.
I assume you want the Count of the row
SELECT Acc_Id, COUNT(*)
FROM Table
GROUP BY Acc_Id
Try this:
select Acc_Id, MAX(Row_No)
from table
group by Acc_Id
As a beginner then this is your first exposure to aggregation and grouping. You may want to look at the documentation on group by now that this problem has motivated your interest in a solutions. Grouping operates by looking at rows with common column values, that you specify, and collapsing them into a single row which represents the group. In your case values in Acc_Id are the names for your groups.
The other answers are both correct in the the final two columns are going to be equivalent with your data.
select Acc_Id, count(*), max(Row_No)
from T
group by Acc_Id;
If you have gaps in the numbering then they won't be the same. You'll have to decide whether you're actually looking for a count of rows of a maximum of a value within a column. At this point you can also consider a number of other aggregate functions that will be useful to you in the future. (Note that the actual values here are pretty much meaningless in this context.)
select Acc_Id, min(Row_No), sum(Row_No), avg(Row_No)
from T
group by Acc_Id;