MS Access convert and summarise two rows into columns with unique names - sql

I'm really struggling to 'Transform' or pivot this simple two column table, is there a way ?
All the solutions I have found so far ( pivot / transform / crosstab etc) require the data to have some kind of third field index number in order to create the column names. In my case each Itemcode can have any number of Itemimage and those itemimage sometimes are valid for more than one Itemcode. Typically the number of itemimage will be less than 20 but there are tens of thousands of Itemcode.
transform Table1:
Itemcode Itemimage
12345 image-a.jpg
12345 image-b.jpg
23456 image-c.jpg
23456 image-d.jpg
23456 image-a.jpg
34567 image-e.jpg
45678 image-a.jpg
into a table like this:
Itemcode Itemimage1 Itemimage2 Itemimage3
12345 image-a.jpg image-b.jpg null
23456 image-c.jpg image-d.jpg image-a.jpg
34567 image-e.jpg null null
45678 image-a.jpg null null
The nearest I have come to getting this to work is
TRANSFORM First(MySubQuery.Itemimage) AS FirstOfItemimage
SELECT MySubQuery.Itemcode
FROM (SELECT [Itemcode], 'Itemimage' & [Number] AS ColumnName, [Itemimage] FROM Table1) AS MySubQuery
GROUP BY MySubQuery.Itemcode
PIVOT MySubQuery.ColumnName;
but this requires the creation of a [Number] column in Table1 to create the incremental index number for the columns.
day 3 of working on this ... beginning to think it cannot be done with a single query and will require a Visual Basic macro to sort into Itemcode order then create an array which is read out to a new table. Really need some help as I have never programed in VB.
note: it is important that the resulting table is in the same order as Table1 This is because the data in Table1 is in a specific order as provided to me by a 3rd party. The sample data above shows only the Itemimage field but I have similar data with Itemdescription containing sentences where the sequence must be maintained in order to keep its grammatical meaning unchanged.

Related

INSERT INTO with foreign key and data from another table

I have a table where the most important information is that it is auto-incremented, the rest of the fields in the database are not relevant. Before inserting the data into the table, I created a "helper" table to store the newly created IDs in this table.
I have a second table like this - also the most important information is that the ID is auto-incremented, and the other data is not relevant to this example. In this case, I have also created an auxiliary table that stores the newly created ID values from this table.
Now I would like to take the values from auxiliary table 1 and 2 and insert them into a third table that will take the smallest ID from auxiliary table 1 and the smallest ID from auxiliary table 2 and insert them as a record into this third table, for example:
Record ID of third table | Smallest ID from first table | Smallest ID from third table.
I have no idea how to build the query constructs in my case - could someone give me some advice, or ready-made (different) code to follow?
My code:
DECLARE #inserted1 TABLE (contact_id udt_id)
INSERT INTO t_usr_contact (contact_firstname, contact_lastname)
OUTPUT INSERTED.contact_id INTO #inserted1(contact_id)
SELECT
'Firma',
'Temporary_value'
FROM t_sup_supplier AS sup
WHERE sup.sup_id IN (175,176) AND sup.grp_id IS null
DECLARE #inserted2 TABLE (grp_id udt_id)
INSERT INTO t_usr_group (grp_label_en)
OUTPUT INSERTED.grp_id INTO #inserted2(grp_id)
SELECT
'Supplier contact'
FROM t_sup_supplier AS sup2
WHERE sup2.sup_id IN (175,176) AND sup2.grp_id IS null
INSERT INTO t_usr_contact_group (grp_id, contact_id)
I would like to go the easiest way, which is as below, but it doesnt work :/.
VALUES (#inserted2.grp_id, #inserted2.contact_id)
As for the data example, after the insert in the first table I will get the following records and in the auxiliary table number 1 I will get the following records:
**Table t_usr_contact:**
175 - Firma - Temporary_value
176 - Firma - Temporary_value
**Table #inserted1:**
175
176
**Table t_usr_group:**
201 - Supplier_contact
202 - Supplier_contact
**Table #inserted2:**
201
202
**Table t_usr_contact_group:**
201 - 175
202 - 176
I've got no idea what you're ultimately trying to do, but if you want two tables each with N rows to become one table made from the columns of the two input tables, like you've got in your example (where your table of 175,176 and your table of 201,202 shall become a table of 175|201,176|202) then you need to join them. To join them you need a key. You haven't got a key so you'll have to fake one:
INSERT INTO thirdtable
SELECT contact_id,grp_id
FROM
(SELECT *, ROW_NUMBER() OVER(ORDER BY contact_id) as FakeKey FROM #inserted1) x
INNER JOIN
(SELECT *, ROW_NUMBER() OVER(ORDER BY grp_id) as FakeKey FROM #inserted2) x
ON x.FakeKey = y.FakeKey
This, of course, joins the data in a very arbitrary fashion based on the order of the assigned IDs. If you want some specific order, like contact 175 exists first and has to get group 202, then you can make the query that inserts the group (eg 202) based on the input 175 output the 175 and the 202 together into a (temp) common table then split it into the detail and middleman tables after

Access Append Query compare with table

I am currently rebuilding a messy Access Database and I entcountered the following problem:
I've got a Table of facilities which contain a row called district. Those Rows contain a number linked to another table which just contains the numbers and names of districts. I added a lookup Column with the Name of the district displayed.
I now want to change the new column for every row depending on the data in the old row.
Facilities
NAME|..|DISTRICT_OLD
A |..| 1
B |..| 2
C |..| 1
...
DISTRICTS
ID|NAME
1 |EAST
2 |WEST
...
I would like something like the following:
Facilities
NAME|..|DISTRICT_OLD|DISTRICT
A |..| 1|EAST
B |..| 2|WEST
C |..| 1|EAST
...
The District Field (lookup) gets its Data like follows SELECT [DISTRICTS].ID, [DISTRICTS].NAME FROM DISTRICTS ORDER BY [NAME];
(Thanks to Gordon Linoff) I could get the query but I do now struggle with the insert. I can get the Data I want:
SELECT [DISTRICTS].NAME FROM Facilities INNER JOIN DISTRICTS ON Facilities.DISTRICT_OLD = [DISTRICTS].ID;
If I try to INSERT INTO Facilities(DISTRICT) It says Typerror.
How can I modify the data to be compatible with a lookup column?
I guess I need to select the ID as well which isnt't a problem but then the error says to many columns.
I hope I haven't mistaken any names, my Access isn't running the english language.
Can you help me?
Fabian
Lookup columns are number (long integer)
with a relational database, you only need the single column containing the ID (as you always lookup the district.name with a query) so:
INSERT INTO Facilities(DISTRICT) SELECT 4
where 4 is the ID of the record in the lookup table that you want, or better still:
INSERT INTO Facilities(DISTRICT)
SELECT ID FROM DISTRICTS
where District.Name = "Name you want the ID for"

How to design a SQL table where a field has many descriptions

I would like to create a product table. This product has unique part numbers. However, each part number has various number of previous part numbers, and various number of machines where the part can be used.
For example the description for part no: AA1007
Previous part no's: AA1001, AA1002, AA1004, AA1005,...
Machine brand: Bosch, Indesit, Samsun, HotPoint, Sharp,...
Machine Brand Models: Bosch A1, Bosch A2, Bosch A3, Indesit A1, Indesit A2,....
I would like to create a table for this, but I am not sure how to proceed. What I have been able to think is to create a table for Previous Part no, Machine Brand, Machine Brand Models individually.
Question: what is the proper way to design these tables?
There are of course various ways to design the tables. A very basic way would be:
You could create tables like below. I added the columns ValidFrom and ValidTill, to identify at which time a part was active/in use.
It depends on your data, if datatype date is enough, or you need datetime to make it more exactly.
CREATE TABLE Parts
(
ID bigint NOT NULL
,PartNo varchar(100)
,PartName varchar(100)
,ValidFrom date
,ValidTill date
)
CREATE TABLE Brands
(
ID bigint NOT NULL
,Brand varchar(100)
)
CREATE TABLE Models
(
ID bigint NOT NULL
,BrandsID bigint NOT NULL
,ModelName varchar(100)
)
CREATE TABLE ModelParts
(
ModelsID bigint NOT NULL
,PartID bigint NOT NULL
)
Fill your data like:
INSERT INTO Parts VALUES
(1,'AA1007', 'Screw HyperFuturistic', '2017-08-09', '9999-12-31'),
(1,'AA1001', 'Screw Iron', '1800-01-01', '1918-06-30'),
(1,'AA1002', 'Screw Steel', '1918-07-01', '1945-05-08'),
(1,'AA1004', 'Screw Titanium', '1945-05-09', '1983-10-05'),
(1,'AA1005', 'Screw Futurium', '1983-10-06', '2017-08-08')
INSERT INTO Brands VALUES
(1,'Bosch'),
(2,'Indesit'),
(3,'Samsung'),
(4,'HotPoint'),
(5,'Sharp')
INSERT INTO Models VALUES
(1,1,'A1'),
(2,1,'A2'),
(3,1,'A3'),
(4,2,'A1'),
(5,2,'A2')
INSERT INTO ModelParts VALUES
(1,1)
To select all parts of a certain date (in this case 2013-03-03) of the "Bosch A1":
DECLARE #ReportingDate date = '2013-03-03'
SELECT B.Brand
,M.ModelName
,P.PartNo
,P.PartName
,P.ValidFrom
,P.ValidTill
FROM Brands B
INNER JOIN Models M
ON M.BrandsID = B.ID
INNER JOIN ModelParts MP
ON MP.ModelsID = M.ID
INNER JOIN Parts P
ON P.ID = MP.PartID
WHERE B.Brand = 'Bosch'
AND M.ModelName = 'A1'
AND P.ValidFrom <= #ReportingDate
AND P.ValidTill >= #ReportingDate
Of course there a several ways to do an historization of data.
ValidFrom and ValidTill (ValidTo) is one of my favourites, as you can easily do historical reports.
Unfortunately you have to handle the historization: When inserting a new row - in example for your screw - you have to "close" the old record by setting the ValidTill column before inserting the new one. Furthermore you have to develop logic to handle deletes...
Well, thats a quite large topic. You will find tons of information in the world wide web.
For the part number table, you can consider the following suggestion:
id | part_no | time_created
1 | AA1007 | 2017-08-08
1 | AA1001 | 2017-07-01
1 | AA1002 | 2017-06-10
1 | AA1004 | 2017-03-15
1 | AA1005 | 2017-01-30
In other words, you can add a datetime column which versions each part number. Note that I added a primary key id column here, which is invariant over time and keeps track of each part, despite that the part number may change.
For time independent queries, you would join this table using the id column. However, the part number might also serve as a foreign key. Off the top of my head, if you were generating an invoice from a previous date, you might lookup the appropriate part number at that time, and then join out to one or more tables using that part number.
For the other tables you mentioned, I do not see a similar requirement.

Transpose table in SQL

I have a table set up in the following manner.
CustomerNumber June15_Order June15_Billing July15_Order July15_Billing August15_Order August15_Billing
12345 5 55 3 45
5431 6 66 5 67
I would prefer it to be:
CustomerNumber Date Order Billing
12345 01/06/2015 5 55
12345 01/07/2015 3 45
5431 01/06/2015 6 66
5431 01/07/2015 5 67
Any thoughts as to how I would accurately transpose this table?
If you're just trying to get the old data into the new, you'll basically need to use brute force:
INSERT INTO NewTable
(CustomerNumber, [Date], [Order], Billing)
(
SELECT CustomerNumber, '06/15/2015', June15_Order, June15_Billing
FROM OldTable
UNION
SELECT CustomerNumber, '07/15/2015', July15_Order, July15_Billing
FROM OldTable
UNION
SELECT CustomerNumber, '08/15/2015', August15_Order, August15_Billing
FROM OldTable
)
Presuming there are columns for any month and any years, this gets ugly really fast. If the columns are set and hard-coded, use #John Pasquet's solution (+1). If you need the ability to work with any set of columns of the form MMMMDD_Type, here's an outline.
First pass:
Write a SELECT... UNPIVOT... query to transform the table
Map the resulting "label" column to a Date datatype and a "Type" (Order, Billing)
However, mapping result set column names of "July15" to "Jul 1, 2015" (or 01/07/2015) is hard, if not crazy hard. This leads to a second pass:
Build a "lookup" list of columns from sys.tables and sys.colmns
Pick out those that are to be unpivoted
Figure out the dates and types for each of them
Build the SELECT... UNPIVOT... in dynamic SQL, dumping the results to a temp table
Join this temp table to the lookup list by original column name, which (via the join) gets you the prepared date and type values
Seriously, this could get ridiculously complex. The smart money is on rebuild the tables with columns for date and type.
First create the a new table with the desired structure, after that you will need to create a stored procedure for that task, which will iterate over all rows.
On the columns you know old_col to new_col just take the value and save in a variable, for the others you will need to create condition for each month like a "contains june" and save in two variables date and value, after that each time you found a new month with value > 0 perform a insert on the new table with all the variables.

SQL Query -- IF X is shared between two strings in a primary composite key?

Not sure how to explain this, as I have only basic SQL knowledge. I need help with some logic to signal a user when a unique string is referenced more than once in a composite primary key.
A table I use contains a composite primary key which ties a unique "ItemCode" to a repeating "WarehouseCode". The "QuantityOnHand" column lists how much we have of an item in each warehouse:
_____PK_______
| |
ItemCode | WarehouseCode | QuantityOnHand
---------------------------------------------
001 A 100
001 B 500
002 A 600
003 B 250
etc.
How do I "signal" (create a boolean value?) when ItemCode 001 is in two separate warehouses?
The end result is a crystal report which somehow alerts the user when an item's total quantity is split between two warehouses.
Thanks
Utilise GROUP BY and HAVING. For example this query will return a list of ItemCodes and a count of how many warehouses they are in where that count is greater than 1.
SELECT ItemCode, COUNT(*)
FROM table
GROUP BY ItemCode
HAVING COUNT(*) > 1
In crystal you would probably want to create a group on ItemCode and then you can evaluate: DistinctCount({table.WarehouseCode}) but I would suggest you use SQL group by ItemCode having count(distinct WarehouseCode) > 1
It is much easier to do in Crystal than in pure SQL
Using a Crystal function:
If {table.ItemCode} = Previous({table.ItemCode})
Then //we have a duplicate ItemCode, do something to flag it
The above assumes that the details have these values and that they were not grouped. Although, even if they were grouped something like this should do it
If {table.ItemCode} = Previous({table.ItemCode})
and {table.WarehouseCode} <> Previous({table.WarehouseCode})
Then //we have a duplicate ItemCode