Select everything from 1 table and only x rows from another - sql

Im making a join query like:
SELECT * FROM Clothes AS C
JOIN Style AS S on C.StyleId = S.SylelId
WHERE ClothesId = '19'
But i dont want to select everything from Style
I want to select everything from Clothes (20 rows)
And only select 1 row (from 10) from Style
What is the easyest way to do this without having to select every row from Clothes (with 20 things to select) like:
SELECT C.Id, C.Description, C.Name, C.Size, C.Brand, S.Name FROM Clothes AS C
JOIN Style AS S on C.StyleId = ST.SylelId
WHERE ClothesId = '19'
What would be the fastest way? Or is this the only possibillity

Add the table name to the *
SELECT C.*, S.Name as StyleName
FROM Clothes AS C
JOIN Style AS S on C.StyleId = S.SylelId
WHERE ClothesId = '19'
If you have equal names in both tables you have to alias at least one of them to distinguish them.

Related

SQL: How to remove duplicate rows created by CASE WHEN statement

I have two tables: (A) customers of the gym and (B) customers of the restaurant. I want to create an indicator in table (A) to indicate the customers who have been to both the gym and the restaurant on the same day. In accomplishing this, I used the following SQL script, but it created duplicate rows:
SELECT *,
CASE WHEN a.GymDate = b.RestaurantDate THEN 'Meal + Gym on the same day'
ELSE 'Gym Only' END AS 'Meal+Gym'
FROM Table_A a
LEFT JOIN Table_B b
ON a.customerid = b.customerid;
May I know how to keep only Table_A, but with the addition of the 'Meal+Gym' Indicator? Thanks!
A case expression does not generate rows, it is your join that is generating the duplicate rows. You could add the date predicate to the join condition, and merely check for the existence of a record, e.g.
SELECT *,
CASE WHEN b.customerid IS NOT NULL THEN 'Meal + Gym on the same day'
ELSE 'Gym Only'
END AS [Meal+Gym]
FROM Table_A a
LEFT JOIN Table_B b
ON a.customerid = b.customerid
AND a.GymDate = b.RestaurantDate;
If table_B is not unique per customer/Date then you may need to do something like this to prevent duplicates:
SELECT *,
CASE WHEN r.RestaurantVisit IS NOT NULL THEN 'Meal + Gym on the same day'
ELSE 'Gym Only'
END AS [Meal+Gym]
FROM Table_A a
OUTER APPLY
( SELECT TOP 1 1
FROM Table_B b
WHERE a.customerid = b.customerid
AND a.GymDate = b.RestaurantDate
) AS r (RestaurantVisit);
N.B. While using single quotes works for column aliases, it is not a good habit at all, because it makes your column aliases indistinguishable from string literals other than from context. Even if this is clear to you, it probably isn't to other people, and since there's about a 10:1 ratio of reading:writing code, writing code that is easy to read is important. As such I've used square brackets for your column name instead
I would start with a table of customers, so you get an indicator for customers who have been to neither the gym nor a restaurant.
Then:
select c.*,
(case when exists (select 1
from table_a a join
table_b b
on a.customerid = b.customerid and
a.GymDate = b.RestaurantDate
where a.customerid = c.customerid
)
then 1 else 0
end) as same_day_gym_restaurant_flag
from customers c;
You can use CASE WHEN EXISTS instead of the LEFT JOIN:
SELECT *,
CASE WHEN EXISTS (
SELECT 1 FROM Table_B b
WHERE a.customerid = b.customerid
AND a.GymDate = b.RestaurantDate)
THEN 'Meal + Gym on the same day'
ELSE 'Gym Only'
END AS 'Meal+Gym'
FROM Table_A a
This assumes that you don't need any data from Table_B in the results.

How can I exclude users who have only purchase with car?

There is this SQL(from Django) query:
SELECT "id", "name"
FROM "polls_client" INNER JOIN "polls_purchases"
ON ("id" = "client_id")
WHERE "polls_purchases"."product" IN (car, bike)
We need to select from query users who have purchase records only 'car'. I want to do this in one select to the database. How do I do this?
You can group by client and set the condition in the HAVING clause:
SELECT pc.id, pc.name
FROM polls_client pc INNER JOIN polls_purchases pp
ON pc.id = pp.client_id
GROUP BY pc.id, pc.name
HAVING SUM(CASE WHEN pp.product <> 'car' THEN 1 ELSE 0 END) = 0
We need to select from query users who have purchase records only 'car'.
The simplest, most efficient method should be not exists:
SELECT c.*
FROM "polls_client" c
WHERE NOT EXISTS (SELECT 1
FROM "polls_purchases" pp
WHERE c."id" = pp."client_id" AND pp."product" <> 'car'
);
In particular, this can take advantage of an index on polls_purchases(client_id, product).
I would also dissuade your from using double quotes for identifies. They only serve to clutter queries.

Double count a column based on another column for join table

This is difficult to explain in the title, but I have a column that's a join table, and I'd like to count the number of books a character has appeared in based the type of book.
So if cb.type = 2, then I want count(cb.id) + 1 if that makes sense. Otherwise for all other types, just count it normally with count(cb.id).
SELECT
CASE
WHEN cb.type = 2 THEN count(cb.id) + 1
ELSE count(cb.id)
END AS book_count,
c.*
FROM characters c
INNER JOIN character_books cb ON cb.character_id = c.id
GROUP BY c.id, cb.type
ORDER BY book_count DESC
The above query does not work because I have to group by c.id, cb.type, and so I'm not getting the total number of books the character has appeared in.
Now without considering the cb.type, the query would look like this:
SELECT count(cb.id) AS book_count, c.*
FROM characters c
INNER JOIN character_books cb ON cb.character_id = c.id
GROUP BY c.id
ORDER BY book_count DESC
However, if the column cb.type = 2 (which is actually a bitwise column, just using the number 2 here for simplicity), then we should be adding an additional count to book_count.
How would I make this happen?
You want conditional aggregation. I think you want:
SELECT c.id,
SUM(CASE cb.type = 2 THEN 2 ELSE 1 END) as book_count
FROM characters c INNER JOIN
character_books cb
ON cb.character_id = c.id
GROUP BY c.id
ORDER BY book_count DESC;

SQL- get data from two tables in different columns without using unions

I have a table STOCK that looks like this:
PRODUCT SALES_CODE STOCK_1 STOCK_2 STOCK_3
-----------------------------------------------------
A 6-10 0 1 2
There are many STOCK_X buckets but for simplicity's sake, I've excluded.
Now I have another table SIZE_GRID:
SALES_CODE SIZE_1 SIZE_2 SIZE_3
--------------------------------------
6-10 6 8 10
As you might have guessed, these are stock on hand for a certain product, by size.
I need to get the STOCK values from the first table, and the size from the second table.
Originally, I was doing the following
SELECT
STOCK.PRODUCT,
SIZE_GRID.SIZE_1,
STOCK.STOCK_1
FROM
STOCK
INNER JOIN
SIZE_GRID ON
SIZE_GRID.SALES_CODE = STOCK.SALES_CODE
UNION ALL
SELECT
STOCK.PRODUCT,
SIZE_GRID.SIZE_2,
STOCK.STOCK_2
FROM
STOCK
INNER JOIN
SIZE_GRID ON
SIZE_GRID.SALES_CODE = STOCK.SALES_CODE
UNION ALL
SELECT
STOCK.PRODUCT,
SIZE_GRID.SIZE_3,
STOCK.STOCK_3
FROM
STOCK
INNER JOIN
SIZE_GRID ON
SIZE_GRID.SALES_CODE = STOCK.SALES_CODE
I have around 40 STOCK_X that I need to retrieve, so wandering if there is a much easier way to do this? Preferably I want to use pure SQL and no UDF/SP's.
http://sqlfiddle.com/#!6/f323e
If you are on SQL Server 2008 or later version, you could try the following method (found here):
SELECT
STOCK.PRODUCT,
X.SIZE,
X.STOCK
FROM
STOCK
INNER JOIN
SIZE_GRID ON
SIZE_GRID.SALES_CODE = STOCK.SALES_CODE
CROSS APPLY (
VALUES
(SIZE_GRID.SIZE_1, STOCK.STOCK_1),
(SIZE_GRID.SIZE_2, STOCK.STOCK_2),
(SIZE_GRID.SIZE_3, STOCK.STOCK_3)
) X (SIZE, STOCK)
;
With a small tweak you could make it work in SQL Server 2005 as well:
SELECT
STOCK.PRODUCT,
X.SIZE,
X.STOCK
FROM
STOCK
INNER JOIN
SIZE_GRID ON
SIZE_GRID.SALES_CODE = STOCK.SALES_CODE
CROSS APPLY (
SELECT SIZE_GRID.SIZE_1, STOCK.STOCK_1
UNION ALL
SELECT SIZE_GRID.SIZE_2, STOCK.STOCK_2
UNION ALL
SELECT SIZE_GRID.SIZE_3, STOCK.STOCK_3
) X (SIZE, STOCK)
;
However, if you are using an even earlier version, this might be of help:
SELECT
STOCK.PRODUCT,
SIZE = CASE X.N
WHEN 1 THEN SIZE_GRID.SIZE_1
WHEN 2 THEN SIZE_GRID.SIZE_2
WHEN 3 THEN SIZE_GRID.SIZE_3
END,
STOCK = CASE X.N
WHEN 1 THEN STOCK.STOCK_1
WHEN 2 THEN STOCK.STOCK_2
WHEN 3 THEN STOCK.STOCK_3
END,
FROM
STOCK
INNER JOIN
SIZE_GRID ON
SIZE_GRID.SALES_CODE = STOCK.SALES_CODE
CROSS JOIN (
SELECT 1
UNION ALL
SELECT 2
UNION ALL
SELECT 3
) X (N)
;
Although the last two options use UNION ALL, they are combining single rows only, not entire subsets
Consider normalizing the table. Instead of a repeating column:
PRODUCT SALES_CODE STOCK_1 STOCK_2 STOCK_3
Use a normalized table:
PRODUCT SALES_CODE STOCK_NO STOCK
And the same for the SIZE_GRID table:
SALES_CODE SIZE_NO SIZE
Now you can query without the need to list 40 columns:
select *
from STOCK s
join SIZE_GRID sg
on sg.SALES_CODE = s.SALES_CODE
and sg.SIZE_NO = s.STOCK_NO
Here are some alternatives you can use:
Execute each SQL separately and merge and sort the result sets within your program
Join the tables.
Use a scalar subquery.
select
select col1, col2, col3 from Table_1 q1,
select col1, col2,
col3 from Table_2 q2 from dual;
Try UNION using FULL OUTER JOIN with the NVL function: It is suggested that this has faster performance than the UNION operator.
select
empno,
ename,
nvl(dept.deptno,emp.deptno) deptno, dname from emp
full outer join
dept
on
(emp.deptno = dept.deptno)
order by 1,2,3,4;

How to get the Sum from three tables? [duplicate]

This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
How to get Sum from two tables?
I have three table first "products" second "items" third "sales"
The first and second tables have the same columns('code','quantity') but the third table has ('code','name') now I want sum quantity from first and second but want also want get name from third table which code is equal.
check my code
Select code, sum(qtd),name
from ( select a.code, a.qtd from product a
union all select b.code, b.qtd from items b
union all select c.name from sales c where b.code=c.code
)
group by code
first two giving me perfect values but third fiction giving error not showing also names.
Hum....
SELECT
sales.name,
(SELECT SUM(products.quantity) FROM products WHERE products.code = sales.code) as products.quantity,
(SELECT SUM(items.quantity) FROM items WHERE items.code = sales.code) as items_quantity,
FROM sales
When using UNION be sure that the columns you want to combine matches with each SELECT statement. The first two SELECT statement works fine because they have the same number of columns. The third one failed because it has only one column.
The following are basic rules for combining the result sets of two (or more) queries by using UNION:
The number and the order of the columns must be the same in all queries.
The data types must be compatible.
From your query, I think you want like this,
SELECT a.code, b.name, SUM(a.qtd) totalSUM
FROM product a
INNER JOIN sales b
ON a.code = b.code
GROUP BY a.code, b.name
UNION
SELECT a.code, b.name, SUM(a.qtd) totalSUM
FROM items a
INNER JOIN sales b
ON a.code = b.code
GROUP BY a.code, b.name
I think you want to do something like this, though it's not clear what the actual requirements are:
select code = t1.code ,
name = t2.name ,
qtd = t1.qtd
from ( select code = t.code ,
qtd = sum( t.qtd )
from ( select a.code, a.qtd from product a
union all select b.code, b.qtd from items b
) t
group by t.code
) t1
join sales t2 where t2.code = t1.code
Cheers!