Ms access duplicated records - sql

I`m having an issue with my MS Access query and I hope you can help me.
I want product "ABC" to have code "6029" if the parent is anything else than "GYF", "RGY" & "DRF".
The mapping looks as follows:
| Output_code | Account | Product | Parent |
+-------------+---------+----------+--------+
| 6029 | income | ABC | |
| 7029 | income | ABC | GYF |
| 7029 | income | ABC | RGY |
| 7029 | income | ABC | DRF |
+-------------+---------+----------+--------+
End result would be:
+-------------+---------+----------+--------+
| 6029 | income | ABC | DTF |
| 6029 | income | ABC | DHS |
| 7029 | income | ABC | GYF |
| 7029 | income | ABC | RGY |
| 7029 | income | ABC | DRF |
+-------------+---------+----------+-------
How it works right now:
+-------------+---------+----------+--------+
| 6029 | income | ABC | DTF |
| 6029 | income | ABC | DHS |
| 7029 | income | ABC | GYF |
| 7029 | income | ABC | RGY |
| 7029 | income | ABC | DRF |
| 6029 | income | ABC | GYF |
| 6029 | income | ABC | RGY |
| 6029 | income | ABC | DRF |
+-------------+---------+----------+--------+
Select A.*, B.Output_Code, "Product" as Comment from Source as A
inner join Mapping as B on (B.Account=A.Account and B.Product = A.Product)
where (B.Parent = "" or B.Parent <> A.Parent);
union all
Select A.*, B.Output_Code, "Product+Parent" as Comment from Source as A
inner join Mapping as B on (B.Account=A.Account and B.Product = A.Product
and A.Parent = B.Parent) where B.Parent <> "";
First part (Product) is not working as expected and combinations like ABC+RGY appear twice with both "6029" and "7029".
I tried using select within select (for this I introduced rowid) and it worked but right now is takes 30 min for my query to process (instead of 5 min).
Select A.*, B.Output_Code, "Product" as Comment from Source as A inner join
Mapping as B on (B.Account=A.Account and B.Product = A.Product)
where (B.Parent = "" or B.Parent <> A.Parent) and A.rowid not in (Select
A.rowid from Source as A inner join Mapping as B on (B.Account=A.Account and
B.Product = A.Product and A.Parent = B.Parent) where B.Parent <> "");
Could you kindly share your ideas on what is the proper way of building the first query so it doesn`t affect the performance so heavily?
I went through the list of questions but couldn`t find anything similar.

"Go for the simple solution, not the perfect one"
SELECT
IIF(Parent IN ('GYF','RGY','DRF'), 7029, 6029) as Output_code
FROM
Product
PS; i don't really do much Access SQL- i might not have used the correct string delimiters etc - you might need to jiggle this query around a bit
Edit: If you're looking to extend the mapping, you should consider a left join instead:
Select s.*, IIF(m.Output_Code IS NULL, 6029, m.output_Code)
FROM
source s
LEFT OUTER JOIN
mapping m
on (m.Account=s.Account and m.Product = s.Product and m.parent = s.parent)
Remove the 6029 row from the mapping table (redundant)
LEFT JOIN connects rows that match, and keeps rows from the left side (source) that don't have a match in the right (map) but puts nulls in the values for the right side. By comparison, an inner join throws away rows that don't have a match. It's the "this row from source has no match in map" quality that we want to leverage
This means the 'GYF','RGY','DRF' rows WILL have a match in the map table, they will not be null, the IIF will be false for those rows, the code from mapping will be used
Other rows will NOT have a match, the m.Output_code for those rows will be NULL, the IIF will be TRUE, the value 6029 will be used

I'll make a couple of assumptions about your base tables.
Your Mapping table looks like this:
| Output_code | Product | Parent |
|-------------|---------|--------|
| 7029 | ABC | DRF |
| 7029 | ABC | GYF |
| 7029 | ABC | RGY |
| 8593 | DEF | XYZ |
Your Source table looks like this:
| Product | Parent |
|---------|--------|
| ABC | DTF |
| ABC | DHA |
| ABC | GYF |
| ABC | RGY |
| ABC | DRF |
| DEF | XYZ |
| DEF | ZXL |
This SQL will return all your Source values with the correct Output_code attached. A Null value is returned where there is no Output_code:
SELECT Mapping.Output_code
, Source.Product
, Source.Parent
FROM Source LEFT JOIN Mapping ON Source.Product = Mapping.Product AND
Source.Parent = Mapping.Parent
| Output_code | Product | Parent |
|-------------|---------|--------|
| | ABC | DTF |
| | ABC | DHA |
| 7029 | ABC | GYF |
| 7029 | ABC | RGY |
| 7029 | ABC | DRF |
| 8593 | DEF | XYZ |
| | DEF | ZXL |
If the only product is ABC and you only want to to replace all NULL values with 6029 you could update the Mapping.Output_code line to NZ(Mapping.Output_code, 6029) to do this.
Nz Function help
SELECT NZ(Mapping.Output_code,6029)
, Source.Product
, Source.Parent
FROM Source LEFT JOIN Mapping ON Source.Product = Mapping.Product AND
Source.Parent = Mapping.Parent
| Expr1000 | Product | Parent |
|----------|---------|--------|
| 6029 | ABC | DTF |
| 6029 | ABC | DHA |
| 7029 | ABC | GYF |
| 7029 | ABC | RGY |
| 7029 | ABC | DRF |
| 8593 | DEF | XYZ |
| 6029 | DEF | ZXL |
But I expect you have more than one product and want product DEF to show a different value if there's no parent available.
To do this add a third table called NoMap that lists the code for any product that doesn't already have one:
| Product | Output_code |
|---------|-------------|
| ABC | 6029 |
| DEF | 7593 |
Primary Key: Product
You can then use this new table to replace any Null values found in your table:
SELECT NZ(Mapping.Output_code, NoMap.Output_code)
, Source.Product
, Source.Parent
FROM (
Source LEFT JOIN Mapping ON Source.Product = Mapping.Product AND
Source.Parent = Mapping.Parent)
LEFT JOIN NoMap ON Source.Product = NoMap.Product
| Expr1000 | Product | Parent |
|----------|---------|--------|
| 6029 | ABC | DTF |
| 6029 | ABC | DHA |
| 7029 | ABC | GYF |
| 7029 | ABC | RGY |
| 7029 | ABC | DRF |
| 8593 | DEF | XYZ |
| 7593 | DEF | ZXL |

You can use this.
Select A.*, NZ(B1.Output_Code, B2.Output_Code) as "Output_Code" from
(Source as A
left join Mapping as B1 on (B1.Account=A.Account and B1.Product = A.Product and B1.Parent = A.Parent ) )
left join Mapping as B2 on (B2.Account=A.Account and B2.Product = A.Product and (B2.Parent Is Null or B2.Parent ="") )

Related

SQL Query - Add column data from another table adding nulls

I have 2 tables, tableStock and tableParts:
tableStock
+----+----------+-------------+
| ID | Num_Part | Description |
+----+----------+-------------+
| 1 | sr37 | plate |
+----+----------+-------------+
| 2 | sr56 | punch |
+----+----------+-------------+
| 3 | sl30 | crimper |
+----+----------+-------------+
| 4 | mp11 | holder |
+----+----------+-------------+
tableParts
+----+----------+-------+
| ID | Location | Stock |
+----+----------+-------+
| 1 | A | 2 |
+----+----------+-------+
| 3 | B | 5 |
+----+----------+-------+
| 5 | C | 2 |
+----+----------+-------+
| 7 | A | 1 |
+----+----------+-------+
And I just want to do this:
+----+----------+-------------+----------+-------+
| ID | Num_Part | Description | Location | Stock |
+----+----------+-------------+----------+-------+
| 1 | sr37 | plate | A | 2 |
+----+----------+-------------+----------+-------+
| 2 | sr56 | punch | NULL | NULL |
+----+----------+-------------+----------+-------+
| 3 | sl30 | crimper | B | 5 |
+----+----------+-------------+----------+-------+
| 4 | mp11 | holder | NULL | NULL |
+----+----------+-------------+----------+-------+
List ALL the rows of the first table and if the second table has the info, in this case 'location' and 'stock', add to the column, if not, just null.
I have been using inner and left join but some rows of the first table disappear because the lack of data in the second one:
select tableStock.ID, tableStock.Num_Part, tableStock.Description, tableParts.Location, tableParts.Stock from tableStock inner join tableParts on tableStock.ID = tableParts.ID;
What can I do?
You can use left join. Here is the demo.
select
s.ID,
Num_Part,
Description,
Location,
Stock
from Stock s
left join Parts p
on s.ID = p.ID
order by
s.ID
output:
| id | num_part | description | location | stock |
| --- | -------- | ----------- | -------- | ----- |
| 1 | sr37 | plate | A | 2 |
| 2 | sr56 | punch | NULL | NULL |
| 3 | sl30 | crimper | B | 5 |
| 4 | mp11 | holder | NULL | NULL |

How to get non-existing rows in many to many relationship

I am having following three tables
products
------------------
| id | name |
------------------
| 1 | Ariel |
| 2 | Milk |
------------------
price_list
-----------------------
| id | name |
-----------------------
| 1 | Trade Price |
| 2 | Net Price |
| 3 | Retail Price |
-----------------------
product_prices (it has only two records for product 'Ariel')
----------------------------------------------
| id | product_id | price_list_id | price |
----------------------------------------------
| 1 | 1 | 1 | 100 |
| 2 | 1 | 2 | 110 |
----------------------------------------------
Desired Result:
------------------------------------------------------------
| id | product_name | prices |
------------------------------------------------------------
| | | | id | price_list_name | price | |
| 1 | Ariel | -------------------------------- |
| | | | 1 | Trade Price | 100 | |
| | | | 2 | Net Price | 110 | |
| | | | 3 | Retail Price | null | |
| | | -------------------------------- |
| | | | id | price_list_name | price | |
| 2 | Milk | -------------------------------- |
| | | | 1 | Trade Price | null | |
| | | | 2 | Net Price | null | |
| | | | 3 | Retail Price | null | |
-------------------------------- |
------------------------------------------------------------
I tried following query to get a cross between products and price_list
SELECT p.id,
p.NAME,
pl.id,
pl.NAME
FROM products p
CROSS JOIN price_list pl
WHERE pl.id NOT IN (SELECT product_id
FROM product_prices)
Any idea how to achieve the desired result?
I think something like this. I changed the names of the fields and tables for short. I also display all the fields.
select * from t1 cross join t2 left join t3 on t1.id = t3.t1_id and t2.id = t3.t2_id order by t1.id, t2.id;
+----+-------+----+--------------+------+-------+-------+-------+
| id | name | id | name | id | t1_id | t2_id | price |
+----+-------+----+--------------+------+-------+-------+-------+
| 1 | Ariel | 1 | Trade Price | 1 | 1 | 1 | 100 |
| 1 | Ariel | 2 | Net Price | 2 | 1 | 2 | 110 |
| 1 | Ariel | 3 | Retail Price | NULL | NULL | NULL | NULL |
| 2 | Milk | 1 | Trade Price | NULL | NULL | NULL | NULL |
| 2 | Milk | 2 | Net Price | NULL | NULL | NULL | NULL |
| 2 | Milk | 3 | Retail Price | NULL | NULL | NULL | NULL |
+----+-------+----+--------------+------+-------+-------+-------+
products -> t1
price_list -> t2
product_prices -> t3

SQL - Custom Select View after Joining Multiple Tables

Very simple question and I just can't seem to figure it out.
I have the two tables below. I would like to write a select query that returns the following
| UID | NAME | DESCRIPTION | CC_CONFIG_UID |
├------+---------+-------------+---------------┤
| xxx | HELLO_1 | NULL | abc |
| yyy | WORLD_1 | NULL | hij |
| aaa | NULL | HELLO_2 | efg |
| bbb | NULL | WORLD_2 | klm |
Table A:
| UID | NAME | CC_CONFIG_UID |
|------+---------+---------------|
| xxx | HELLO_1 | abc |
| yyy | WORLD_1 | hij |
Table B:
| UID | DESCRIPTION | CC_CONFIG_UID |
|------+-------------+---------------|
| aaa | HELLO_2 | efg |
| bbb | WORLD_2 | klm |
I have tried
(SELECT * FROM A) UNION (SELECT * FROM B)
But I get the following in return, which is close but not what I need:
| UID | NAME | CC_CONFIG_UID |
├------+---------+---------------┤
| xxx |HELLO_1 | abc |
| aaa |HELLO_2 | def |
| yyy |WORLD_1 | hig |
| bbb |WORLD_2 | klm |
You need to specify the columns. Your tables have three columns, but you want the result set to have four:
select a.uid, a.name, null as description, a.cc_config_uid
from a
union all
select b.uid, null as name, bdescription, b.cc_config_uid
from b;

How do i can convert Column Values Into Row?

Here I'm having table 'TABLE_1' as
|ID | Name | ACID1 | ACVALUE1 | ACID2 | ACVALUE2 | ACID3 | ACVALUE3 |
|----------------------------------------------------------------------
| 1 |ABC | 10 | 82.50 | 20 | 175.95 | 40 | 125.75 |
| 2 |IJK | 30 | 120.55 | 20 | 68.30 | 50 | 25.45 |
| 3 |LMN | 40 | 62.50 | 10 | 87.25 | 30 | 40.50 |
----------------------------------------------------------------------
Another table is AC_TABLE whose ID is recored in above table as ACID1,ACID2,...
___________________
|ID | Name |
|-------------------
|10 | AC1 |
|20 | AC2 |
|30 | AC3 |
|40 | AC4 |
|50 | AC5 |
-------------------
Now what all i want the result in following format
_____________________________
ID | Name | ACName | ACVALUE
------------------------------
1 | ABC | AC1 | 82.50
1 | ABC | AC2 | 175.95
1 | ABC | AC4 | 125.75
2 | IJK | AC3 | 120.55
2 | IJK | AC2 | 68.30
2 | IJK | AC5 | 25.45
3 | LMN | AC4 | 62.50
3 | LMN | AC1 | 87.25
3 | LMN | AC3 | 40.50
-------------------------------
Please help me to get the desired result.
Use Cross Apply to unpivot multiple columns.
First unpivot the Table_1 using cross apply then join the result with the ac_table table. Try this.
SELECT a.id,
a.name,
b.name AS ACName,
cs.ACValue
FROM Table_1 a
CROSS apply (VALUES (ACVALUE1,ACID1),
(ACVALUE2,ACID2),
(ACVALUE3,ACID3))cs(acvalue, ac)
JOIN ac_table b
ON cs.ac = b.id
SQLFIDDLE DEMO

SQL Join setting value from table2 to table1 where id is the same

i've the following table
+-----+------+
| sID | name |
+-----+------+
| 2 | MXX |
| 3 | ISS |
| 4 | FSS |
| 5 | SSA |
| 6 | PSA |
+-----+------+
and the following table
+-----+-------+
| sID | pname |
+-----+-------+
| 1 | qqq |
| 1 | yyy |
| 2 | zzz |
| 1 | lll |
| 2 | mmm |
| 3 | ttt |
| 3 | sss |
| 5 | xxx |
| 5 | iii |
+-----+-------+
and the join result should look like
+-----+-------+----------+
| sID | pname | supplier |
+-----+-------+----------+
| 1 | qqq | |
| 1 | yyy | |
| 2 | zzz | MXX |
| 1 | lll | |
| 2 | mmm | MXX |
| 3 | ttt | ISS |
| 3 | sss | ISS |
| 5 | xxx | SSA |
| 5 | iii | SSA |
+-----+-------+----------+
idea is to put the values of column name from first table in the second table where sID is the same
i tried Select * From TABLE1 c LEFT join TABLE2 T on c.sID=T.sID
Your left join is the wrong way around.
select table2.sid, pname, table1.name as supplier
from table2
left join table1 on table2.sid = table1.sid
or change your left join to a right join