Select from a concatenation of two columns after a left join - sql

Problem description
Let the tables C and V have those values
>> Table V <<
| UnID | BillID | ProductDesc | Value | ... |
| 1 | 1 | 'Orange Juice' | 3.05 | ... |
| 1 | 1 | 'Apple Juice' | 3.05 | ... |
| 1 | 2 | 'Pizza' | 12.05 | ... |
| 1 | 2 | 'Chocolates' | 9.98 | ... |
| 1 | 2 | 'Honey' | 15.98 | ... |
| 1 | 3 | 'Bread' | 3.98 | ... |
| 2 | 1 | 'Yogurt' | 8.55 | ... |
| 2 | 1 | 'Ice Cream' | 7.05 | ... |
| 2 | 1 | 'Beer' | 9.98 | ... |
| 2 | 2 | 'League of Legends RP' | 40.00 | ... |
>> Table C <<
| UnID | BillID | ClientName | ... |
| 1 | 1 | 'Alexander' | ... |
| 1 | 2 | 'Tom' | ... |
| 1 | 3 | 'Julia' | ... |
| 2 | 1 | 'Tom' | ... |
| 2 | 2 | 'Alexander' | ... |
Table C have the values of each product, which is associated with a bill number. Table V has the relationship between the client name and the bill number. However, the bill number has a counter that is dependent on the UnId, which is the store unity ID. That being said, each store has it`s own Bill number 1, number 2, etc. Also, the number of bills from each store are not equal.
Solution description
I'm trying to make select between the C left join V without sucess. Because each BillID is dependent on the UnID, I have to make the join considering the concatenation between those two columns.
I've used this script, but it gives me an error.
SELECT
SUM(C.Value),
V.ClientName
FROM
C
LEFT JOIN
V
ON
CONCAT(C.UnID, C.BillID) = CONCAT(V.UnID, V.BillID)
GROUP BY
V.ClientName
and SQL server returns me this 'CONCAT' is not a recognized built-in function name.
I'm using Microsoft SQL Server 2008 R2
Is the use of CONCAT wrong? Or is it the way I tried to SELECT? Could you give me a hand?
[OBS: The tables I've present you are just for the purpose of explaining my difficulties. That being said, if you find any errors in the explanation, please let me know to correct them.]

You should be joining on the equality of the UnID and BillID columns in the two tables:
SELECT
c.ClientName,
COALESCE(SUM(v.Value), 0) AS total
FROM C c
LEFT JOIN V v
ON c.UnID = v.UnID AND
c.BillID = v.BillID
GROUP BY
c.ClientName;
In theory you could try joining on CONCAT(UnID, BillID). However, you could run into problems. For example, UnID = 1 with BillID = 23 would, concatenated together, be the same as UnID = 12 and BillID = 3.
Note: We wrap the sum with COALESCE, because should a given client have no entries in the V table, the sum would return NULL, which we then replace with zero.

concat is only available in sql server 2012.
Here's one option.
SELECT
SUM(C.Value),
V.ClientName
FROM
C
LEFT JOIN
V
ON
cast(C.UnID as varchar(100)) + cast(C.BillID as varchar(100)) = cast(V.UnID as varchar(100)) + cast(V.BillID as varchar(100))
GROUP BY
V.ClientName

Related

How to insert records based on another table value

I have the following three tables:
Permission
| PermissionId | PermissionName |
+--------------+----------------+
| 1 | A |
| 2 | B |
| 3 | C |
| 100 | D |
Group
| GroupId | GroupLevel | GroupName |
+---------+------------+----------------------+
| 1 | 0 | System Administrator |
| 7 | 0 | Test Group 100 |
| 8 | 20 | Test Group 200 |
| 9 | 20 | test |
| 10 | 50 | TestGroup01 |
| 11 | 51 | TestUser02 |
| 12 | 52 | TestUser03 |
GroupPermission
| GroupPermissionId | FkGroupId | FkPermissionId |
+-------------------+-----------+----------------+
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 3 | 1 | 3 |
| 4 | 1 | 4 |
I need to insert records into GroupPermission table, if table Group, GroupLevel column have 0
then I need to take its GroupId and need to insert values to GroupPermission table as that particular id and 100.
In order to above sample table records, I need to insert the following two records to GroupPermission table,
| FkGroupId | FkPermissionId |
+-----------+----------------+
| 1 | 100 |
| 7 | 100 |
How can I do it
This question is not very clear and I can only assume the value 100 is a static value and that you don't actually have foreign keys as the names of the columns imply. Also, you really should avoid reserved words like "Group" for object names. It makes things more difficult and confusing.
The simple version of your insert might look like this.
insert GroupPermission
(
FkGroupId
, FkPermissionId
)
select g.GroupId
, 100
from [Group] g
where g.GroupLevel = 0
--EDIT--
Since you want to only insert those rows that don't already exist you can use NOT EXISTS like this.
select g.GroupId
, 100
from [Group] g
where g.GroupLevel = 0
AND NOT EXISTS
(
select *
from GroupPermission gp
where gp.FkGroupId = g.GroupId
and g.FkPermissionId = 100
)
Or you could use a left join like this.
select g.GroupId
, 100
from [Group] g
left join GroupPermission gp on gp.FkGroupId = g.GroupId
and gp.FkPermissionId = 100
where g.GroupLevel = 0
and gp.FkGroupId is null

MS Access SQL - Aggregate Count with 2 Example Table

I have a situation where I need to query from a 2 table in MS Access.
I'm new to this SQL access.
Table: UserInfo
===================
| UserID | Gender |
===================
| K01 | M |
| K02 | M |
| K03 | F |
| K04 | M |
===================
Table: OrderInfo
===================================
| OrderID | Type | UserID_FK |
===================================
| 1 | Food | K01 |
| 2 | Food | K01 |
| 3 | Toolkit | K02 |
| 4 | Food | K04 |
| 5 | Toolkit | K03 |
===================================
The question is:
I want to query so the result produce this table, how can I do it in MS Access?
I'm thinking that I should do a subquery but I don't know how to do it.
Table: Summary
================================================================
| UserID | Gender | CountOfToolkit | CountOfFood | TotalCount |
================================================================
| K01 | M | 0 | 2 | 2 |
| K02 | M | 1 | 0 | 1 |
| K03 | F | 1 | 0 | 1 |
| K04 | M | 0 | 1 | 1 |
================================================================
First, Type is a reserved word in MS Access.
You should avoid using reserved words.
Having said that, try this:
SELECT a.UserID, a.Gender, SUM(IIF(b.[Type] ='Food',1,0)) AS CountOfFood, SUM(IIF(b.[Type] ='Toolkit',1,0)) AS CountOfToolkit, COUNT(*) AS TotalCount
FROM UserInfo a INNER JOIN OrderInfo b ON a.UserId = b.UserID_FK
GROUP BY a.UserID, a.Gender
This crosstab query doesn't rely on having just Food & Toolkit as your types - it will count any new types you add.
The NZ wrapped around the Count(sType) ensures the 0 values are shown, while the CLNG ensures it's still treated as a number rather than text.
You could just use Count(sType) AS CountOfType.
TRANSFORM CLNG(NZ(Count(sType),0)) AS CountOfType
SELECT UserID
,Gender
,COUNT(sType) AS TotalCount
FROM UserInfo LEFT JOIN OrderInfo ON UserInfo.UserID = OrderInfo.UserID_FK
GROUP BY UserID, Gender
PIVOT sType

SQL Query to Work out Every Product Combination

I require a SQL query to work out every product combination.
I have three product categories (game, accessory, upgrade) and products assigned to each of these three categories:
+----+------------+-----------+------------+
| id | category | product | prod_code |
+----+------------+-----------+------------+
| 1 | game | GTA | 100 |
| 2 | game | GTA1 | 200 |
| 3 | game | GTA2 | 300 |
| 4 | accessory | Play Pad | 400 |
| 5 | accessory | Xbox Pad | 500 |
| 6 | upgrade | Memory | 600 |
| 6 | upgrade | drive | 700 |
+----+------------+-----------+------------+
I want to take one product from each of the categories and work out every single combination:
+----+--------------+
| id | combinations |
+----+--------------+
| 1 | 100,400,600 |
| 2 | 100,500,600 |
| 3 | 100,400,700 |
| 4 | 100,500,700 |
| ? | etc |
+----+--------------+
How would I go about doing this?
Thanks in advance, Stuart
Use a CROSS JOIN:
SELECT CONCAT(t1.[prod_code], ',',
t2.[prod_code], ',',
t3.[prod_code])
FROM (
SELECT [prod_code]
FROM mytable
WHERE category = 'game') AS t1
CROSS JOIN (
SELECT [prod_code]
FROM mytable
WHERE category = 'accessory') AS t2
CROSS JOIN (
SELECT [prod_code]
FROM mytable
WHERE category = 'upgrade') AS t3
ORDER BY t1.[prod_code], t2.[prod_code], t3.[prod_code]
CROSS JOIN of derived tables, one for each category, produces the following cartesian product: 'game' products x 'accessory' products x 'upgrade' products
Demo here

Combining two view into one result set with transform?

I have a couple of views that generates the following two outputs in SQL Server.
First one (Flats output) shows the number of flats in a particular town with Tileroofs and Brickwalls. Second one shows the same, but for houses.
What I'm trying to do is to create a final table that looks like the 3rd example where the flats and house counts are combined with the corresponding Tileroof and Brickwall combinations.
I have tried union and then grouping, but I'm really struggling to get the Flats and Houses count columns side by side. Is anyone able to help please?
Thanks
--View one
| Town | Flats | TileRoofs | Brick Wall |
-----------------------------------------
| A | 3 | Y | N |
| A | 4 | N | Y |
| A | 8 | N | N |
--View two
| Town | Houses | TileRoofs | Brick Wall |
------------------------------------------
| A | 1 | Y | Y |
| A | 2 | Y | N |
| A | 5 | N | Y |
| A | 2 | N | N |
--Prefered output, by combining the two--
| Town | Flats | Houses | TileRoofs | Brick Wall |
--------------------------------------------------
| A | 0 | 1 | Y | Y |
| A | 3 | 2 | Y | N |
| A | 4 | 5 | N | Y |
| A | 8 | 2 | N | N |
Full outer join might help here.
select isnull(a.Town, b.Town) Town,
isnull(a.TileRoofs, b.TileRoofs) TileRoofs,
isnull(a.[Brick wall], b.[Brick wall]) [Brick wall],
isnull(a.Flats, 0) Flats,
isnull(b.Houses, 0) Houses
from ViewOne a
full outer join ViewTwo b
on a.Town = b.Town
and a.TileRoofs = b.TileRoofs
and a.[Brick wall] = b.[Brick wall]
select
v2.Town ,coalesce(v1.flat,0) as flat,v2.houses,v2.TileRoofs, v2.Brick, v2.Wall
from
view2 as v2 left join view1 as v1
on v1.town=v2.town
You may be after a full outer join
select
houses.town,
flats.flats,
houses.houses,
houses.BrickWall,
houses.TileRoofs
from flats
full outer join houses
on houses.town=flats.town
and houses.TileRoofs = flats.TileRoofs
and houses.BrickWall = flats.BrickWall

Getting Sum of MasterTable's amount which joins to DetailTable

I have two tables:
1. Master
| ID | Name | Amount |
|-----|--------|--------|
| 1 | a | 5000 |
| 2 | b | 10000 |
| 3 | c | 5000 |
| 4 | d | 8000 |
2. Detail
| ID |MasterID| PID | Qty |
|-----|--------|-------|------|
| 1 | 1 | 1 | 10 |
| 2 | 1 | 2 | 20 |
| 3 | 2 | 2 | 60 |
| 4 | 2 | 3 | 10 |
| 5 | 3 | 4 | 100 |
| 6 | 4 | 1 | 20 |
| 7 | 4 | 3 | 40 |
I want to select sum(Amount) from Master which joins to Deatil where Detail.PID in (1,2,3)
So I execute the following query:
SELECT SUM(Amount) FROM Master M INNER JOIN Detail D ON M.ID = D.MasterID WHERE D.PID IN (1,2,3)
Result should be 20000. But I am getting 40000
See this fiddle. Any suggestion?
You are getting exactly double the amount because the detail table has two occurences for each of the PIDs in the WHERE clause.
See demo
Use
SELECT SUM(Amount)
FROM Master M
WHERE M.ID IN (
SELECT DISTINCT MasterID
FROM DETAIL
WHERE PID IN (1,2,3) )
What is the requirement of joining the master table with details when you have all your columns are in Master table.
Also, isnt there any FK relationhsip defined on these tables. Looking at your data it seems to me that there should be FK on detail table for MasterId. If that is the case then you do not need join the table at all.
Also, in case you want to make sure that you have records in details table for the records for which you need sum and there is no FK relationship. Then you could give a try for exists instead of join.