Merge results from two tables through 1 common column - sql-server

We have some warehouses which we do inventory on a regular basis.
I need to make a report (the goal is to use Microsoft PowerBi) to show the discrepancies between different inventories for the same warehouse (location), but the only common column is the warehouse number.
Product column is dynamically: it may appear on an inventory and not on another (and that is exactly what we need to know)
Each inventory is on a different table, like this:
TABLE A
LOCATION PRODUCTS QTY
WH 1 PRODUCT NO. 1 10
WH 1 PRODUCT NO. 2 100
WH 1 PRODUCT NO. 333 5
WH 2 PRODUCT NO. YYY 22
TABLE B
LOCATION PRODUCTS QTY
WH 1 PRODUCT NO. 1 10
WH 1 PRODUCT NO. 2 100
WH 1 PRODUCT NO. 333 5
WH 1 PRODUCT NO. XXX 77
WH 2 PRODUCT NO. YYY 45
WH 1 PRODUCT NO. YYY 555
WH 2 PRODUCT NO. 1 14
Expected output should be like this:
Location products QTY A QTY B
WH 1 PRODUCT NO. 1 10 10
WH 1 PRODUCT NO. 2 100 100
WH 1 PRODUCT NO. 333 5 5
WH 1 PRODUCT NO. XXX - 77
WH 1 PRODUCT NO. YYY - 555
WH 2 PRODUCT NO. 1 - 14
WH 2 PRODUCT NO. YYY 22 45
I´ve read about FULL OUTER JOIN and also PIVOT TABLES, but I was unable to fully understand and use them (and I´m also not sure they are the goal here).
SQL version is Microsoft SQL Server 2016 Standard

One option is a Union ALL in concert with a PIVOT or Conditional Aggregation
Example
Select *
From (
Select Location
,Products
,Qty
,Col = 'Qty A'
From Table A
Union All
Select Location
,Products
,Qty
,Col = 'Qty B'
From Table B
) src
Pivot (sum(Qty) for Col in ([Qty A],[Qty B] ) ) pvt

Isn't this a simple full join? Am I missing something? Pivot seems unnecessary here.
select isnull(A.location,B.location) location, isnull(A.products, B.products) products,
A.QTY A_QTY, B.QTY B_QTY
from tableA A
full outer join tableB B
on A.location = B.location
and A.products = B.products
A_QTY or B_QTY will be null if it's in one table but not the other.

Try this:
;with tableA (LOCATION, PRODUCTS, QTY)
as
(
select 'WH 1','PRODUCT NO. 1',10
union all
select 'WH 1','PRODUCT NO. 2',100
union all
select 'WH 1','PRODUCT NO. 333',5
union all
select 'WH 2','PRODUCT NO. YYY',22
)
, tableB (LOCATION, PRODUCTS, QTY)
as
(
select 'WH 1','PRODUCT NO. 1',10
union all
select 'WH 1','PRODUCT NO. 2',100
union all
select 'WH 1','PRODUCT NO. 333',5
union all
select 'WH 1','PRODUCT NO. XXX',77
union all
select 'WH 2','PRODUCT NO. YYY',45
union all
select 'WH 1','PRODUCT NO. YYY',555
union all
select 'WH 2','PRODUCT NO. 1',14
)
select
LOCATION
, PRODUCTS
, isnull(QtyA,0) [Qty A]
, isnull(QtyB,0) [Qty B]
from
(
select
LOCATION
, PRODUCTS
, QTY
, 'QtyA' ColumnQty
from tableA
union all
select
LOCATION
, PRODUCTS
, QTY
, 'QtyB' ColumnQty
from tableB
) source
pivot
(
sum(QTY) for ColumnQty in ([QtyA],[QtyB])
) pvt
I've tested it and it works as can be seen here.

Related

How to select the value from the table based on category_id USING SQL SERVER

How to select the value from the table based on category_id?
I have a table like this. Please help me.
Table A
ID Name category_id
-------------------
1 A 1
2 A 1
3 B 1
4 C 2
5 C 2
6 D 2
7 E 3
8 E 3
9 F 3
How to get the below mentioned output from table A?
ID Name category_id
--------------------
1 A 1
2 A 1
4 C 2
5 C 2
7 E 3
8 E 3
Give a row number for each row based on group by category_id and sort by ascending order of ID. Then select the rows having row number 1 and 2.
Query
;with cte as (
select [rn] = row_number() over(
partition by [category_id]
order by [ID]
), *
from [your_table_name]
)
select [ID], [Name], [category_id]
from cte
where [rn] < 3;
Kindly run this query It really help You Out.
SELECT tbl.id,tbl.name, tbl.category_id FROM TableA as tbl WHERE
tbl.name IN(SELECT tbl2.name FROM TableA tbl2 GROUP BY tbl2.name HAVING Count(tbl2.name)> 1)
Code select all category_id from TableA which has Name entries more then one. If there is single entry of any name group by category_id then such data will be excluded. In above example questioner want to eliminate those records that have single Name entity like wise category_id 1 has name entries A and B among which A has two entries and B has single entry so he want to eliminate B from result set.

How to join query in sql-server

I have three tables:
Table 1 : Emplyee Details
E_Id Name Department
1 A Manager
2 B Manager
3 C Manager
4 D Engineer
5 E Engineer
6 F Engineer
Table 2 : Salary Details
Sl_Id Name Amount
1 Bsaic_Mng 30000
2 Basic_ENG 20000
Table 3 : Employee Salary
ES_Id E_Id Sl_Id
1 1 1
2 2 1
3 4 2
4 5 2
Here in Table3 field E_ID is a reference to Table1.E_Id
and SL_ID is a reference to Table2.SL_id.
So I wanto Result Which Employee Has Not Salary Define Like E_Id 3 AND 6
You can achieve it as below:
Employee whose salary is not defined in EmployeeSalary table
SELECT *
FROM Emplyee
WHERE E_Id NOT IN (
SELECT E_Id
FROM EmployeeSalary
)
JOIN is not required here
You can do it using a LEFT JOIN like following.
SELECT ED.* FROM
[Emplyee Details] ED
LEFT JOIN [Employee Salary] ES ON ES.E_ID=ED.E_Id
WHERE ES.E_ID IS NULL
I feel NOT EXISTS should be a better option to achieve this for this case.
SELECT * FROM
[Emplyee Details] ED
WHERE NOT EXISTS
(
SELECT 1 FROM [Employee Salary] ES WHERE ES.E_ID=ED.E_Id
)

How to pick multiple values from the table and add them dynamically for picking another column

SELECT
AgentID,Seat1,SeatUpdated_1,Seat2,SeatUpdated_2,
Seat3,SeatUpdated_3,nTimesSeatChanged,
DATEDIFF(MS,(F.SeatUpdated_1),(F.SeatUpdated_3)) AvgTime
FROM ##final F
Now I have to pick SeatUpdated_3 in the diff function based on column nTimesSeatChanges.
If it have value 2 for any agent, the selected column should be SeatUpdated_2
From the limited information would look at how you store the information first of all. It looks like you are storing related values across column. It would be simpler to work with if you looked at storing them as rows.
Current:
AgentID Seat1 SeatUpdated_1 Seat2 SeatUpdated_2 Seat3 SeatUpdated_3 nTimesSeatChanged
------- ----- ------------- ----- ------------- ----- ------------- -----------------
1 11 21 01/02/2015 31 01/03/2015 2
TO :
TableKey AgentID Seat SeatUpdated
-------- ------- ---- -----------
1 1 11 01/01/2015
2 1 12 01/02/2015
3 1 13 01/03/2015
4 2 22 02/02/2015
5 2 23 02/03/2015
Then work in simple queries to get the end result. I'm not an expert by any means but this is how I would approach it.
;
--Some sample data
WITH CTE_DATA as
(
SELECT '1' as TableKey, '1' as 'AgentID','11' as'Seat','01/01/2015' as 'SeatUpdated'
UNION
SELECT '2','1','12','01/02/2015'
UNION
SELECT '3','1','13','01/03/2015'
UNION
SELECT '4','2','22','02/02/2015'
UNION
SELECT '5','2','23','02/03/2015'
)
,
--Get Min Seat
CTE_Min AS (
SELECT AgentID
,MIN(Seat) AS min_seat
FROM CTE_DATA
GROUP BY AgentID
)
--Get max seat
,CTE_Max AS (
SELECT AgentID
,MAX(Seat) AS max_seat
FROM CTE_DATA
GROUP BY AgentID
)
--Stick them together
,CTE_Join AS (
SELECT Min.AgentID
,Min.min_seat
,max.max_seat
FROM CTE_Min min
JOIN CTE_Max max ON min.AgentID = max.AgentID
)
--Get the date
,CTE_JoinDate AS (
SELECT j.*
,d1.SeatUpdated AS min_date
,d2.SeatUpdated AS max_date
FROM CTE_Join j
LEFT JOIN CTE_DATA d1 ON j.AgentID = d1.AgentID
AND j.min_seat = d1.Seat
LEFT JOIN CTE_DATA d2 ON j.AgentID = d2.AgentID
AND j.max_seat = d2.Seat
)
--Work out nSeats
,CTE_nSeats AS (
SELECT AgentID
,COUNT(1) AS nSeats
FROM CTE_DATA
GROUP BY AgentID
)
--Final result set
SELECT j.*
,DATEDIFF(DAY, min_date, max_date) AS DIFF_Days
,n.nSeats
FROM CTE_JoinDate j
LEFT JOIN CTE_nSeats n ON j.AgentID = n.AgentID

SQL Server 2008 how to select top [column value] and random record?

I'm using SQL Server 2008, I want select random row record, and the total number of record is depend on another table's column value, how to do this?
My SQL statement is something like this, but wrong..
select top b.number a.name, a.link_id
from A a
left join B b on b.link_id = a.link_id
order by newid()
Here are my tables and the expected result.
Table A:
name link_id
james 100
albert 100
susan 100
simon 101
tom 101
fion 101
Table B:
link_id number
100 2
101 1
Expected result:
when run 1st time, result may be:
name link_id
james 100
susan 100
fion 101
2nd time result may be:
albert 100
susan 100
simon 101
3rd time could be:
james 100
albert 100
fion 101
Explaination
Refer to table B, link_id: 100, number: 2
meaning that Table A should select out 2 random record for link_id = 100
and need to select 1 random record for link_id=101
You can use the ROW_NUMBER() function:
SELECT A.name, A.link_id
FROM(
SELECT name,link_id, ROW_NUMBER()OVER(PARTITION BY link_id ORDER BY NEWID()) rn
FROM dbo.tblA
) AS A
JOIN dbo.tblB AS B
ON A.link_id = B.link_id
WHERE A.rn <= B.number;
Here is a SqlFiddle to show this in action: http://sqlfiddle.com/#!3/92eac/2
Try this:
SELECT a.*
FROM b
CROSS APPLY
(
SELECT TOP (b.number) a.*
FROM a
WHERE a.link_id = b.link_id
ORDER BY
NEWID()
) a
Also see: SQLFiddle

sql select from multiple records only the most recent

i have a table named customer_age that loks like this:
ID 1 2 3 4 5 6 7 8 9
NAME JIM JIM JIM NICK NICK NICK Paul Paul Paul
VALUE 20 13 12 10 20 8 4 24 14
and i want to display only the first record from each name. Something like this
ID 1 4 7
NAME JIM NICK Paul
VALUE 20 10 4
So far i have not been able to work it out.
i use sql server 2005
Any help would be appreciated...
Try using a subselect to find the lowest ID for each name, and use that set of IDs to pull the records from the main table:
SELECT ID, Name, Value
FROM customer_age
WHERE ID IN
(
SELECT MIN(ID) AS ID
FROM customer_age
GROUP BY Name
)
Just select the first record for each name using cross apply:
SELECT
ca.ID, ca.NAME, ca.VALUE
FROM customer_age c
CROSS APPLY (SELECT TOP 1 ID, NAME, VALUE
FROM customer_age ca
WHERE ca.NAME = c.NAME ORDER BY ID) ca
ORDER BY ca.ID
How about using window functions??
SELECT Id, Name, Value
FROM (
SELECT Id, Name, Value, ROW_NUMBER() OVER (PARTITION BY Name ORDER BY Id ASC) AS rowNum
FROM customer_age
) AS sub
WHERE rowNum = 1
Assuming first record means highest ID, you may try your query with descending orderby ID and TOP n.

Resources