I have and issue in my query don't return correct data when I compare some values
select a.item, iif(a.value>b.value,0,1) as compare
from table a left join table b on a.id=b.id
return
item1, 0
item2, 0
item3, 0
and my data is
table a
item1 10
item2 20
item3 30
table b
item1 5
item2 25
item3 30
expected correct result was
item1, 0
item2, 1
item3, 0
and when I use ISNULL() function return
item1, 1
item2, 1
item3, 1
happened the same problem with CASE WHEN ... THEN 0 ELSE 1 END
I really don't know what's happened with the query I don't find where is the problem any help very thanks in advance.
It looks like you're joining the same table onto itself, i.e.:
table a
This refers to a table called 'table', aliased as 'a'.
If you are joining the same table onto itself, this will account for your result of everything returning 1, as, assuming a one-to-one match, a.value and b.value will always be equal.
Are you looking for something more like:
[table a] a left join [table b] b on a.id = b.id
Should be Inner join and using [for spaced table names or columns]
SELECT
a.item,
iif(a.value > b.value, 0, 1) AS compare
FROM [table a] a
INNER JOIN [table b] b
ON a.id = b.id
Related
I have table with self-related foreign keys and can not get how I can receive firs child or descendant which meet condition. My_table structure is:
id
parent_id
type
1
null
union
2
1
group
3
2
group
4
3
depart
5
1
depart
6
5
unit
7
1
unit
I should for id 1 (union) receive all direct child or first descendant, excluding all groups between first descendant and union. So in this example as result I should receive:
id
type
4
depart
5
depart
7
unit
id 4 because it's connected to union through group with id 3 and group with id 2 and id 5 because it's connected directly to union.
I've tried to write recursive query with condition for recursive part: when parent_id = 1 or parent_type = 'depart' but it doesn't lead to expected result
with recursive cte AS (
select b.id, p.type_id
from my_table b
join my_table p on p.id = b.parent_id
where b.id = 1
union
select c.id, cte.type_id
from my_table c
join cte on cte.id = c.parent_id
where c.parent_id = 1 or cte.type_id = 'group'
)
Here's my interpretation:
if type='group', then id and parent_id are considered in the same group
id#1 and id#2 are in the same group, they're equals
id#2 and id#3 are in the same group, they're equals
id#1, id#2 and id#3 are in the same group
If the above is correct, you want to get all the first descendent of id#1's group. The way to do that:
Get all the ids in the same group with id#1
Get all the first descendants of the above group (type not in ('union', 'group'))
with recursive cte_group as (
select 1 as id
union all
select m.id
from my_table m
join cte_group g
on m.parent_id = g.id
and m.type = 'group')
select mt.id,
mt.type
from my_table mt
join cte_group cg
on mt.parent_id = cg.id
and mt.type not in ('union','group');
Result:
id|type |
--+------+
4|depart|
5|depart|
7|unit |
Sounds like you want to start with the row of id 1, then get its children, and continue recursively on rows of type group. To do that, use
WITH RECURSIVE tree AS (
SELECT b.id, b.type, TRUE AS skip
FROM my_table b
WHERE id = 1
UNION ALL
SELECT c.id, c.type, (c.type = 'group') AS skip
FROM my_table c
JOIN tree p ON c.parent_id = p.id AND p.skip
)
SELECT id, type
FROM tree
WHERE NOT skip
I need to return some data which contains the values I need, plus more. How can i retrieve the data, excluding the values that I don't need, which exists elsewhere?
Or if this is not possible, the variations of values that needs to be removed are from 5 possibilities, therefore can I 'replace' any occurrence of the 5?
For example:
TABLE1
ID ITEM
-------------------------
1 AAA:CAR
2 BBB:PLANE
3 AAA:BIKE
4 BBB:TRAIN
5 CCC:BUS
I think the below will remove AAA: from the result
SELECT ITEM REPLACE(ITEM, 'AAA:', '')
FROM TABLE1
Assume this would return
ITEM
----------
CAR
BBB:PLANE
BIKE
BBB:TRAIN
CCC:BUS
However I want to replace AAA: and BBB: and CCC: with '' where AAA: or BBB: or CCC: exist elsewhere, for example here:
TABLE2
ID THING
-----------------
1 AAA:
2 BBB:
3 CCC:
4 DDD:
5 EEE:
For example:
SELECT ITEM REPLACE(ITEM, '/* where THING ID exists in TABLE2 BETWEEN 1 and 5 */', '')
FROM TABLE1
Or if this is not possible, to state any variation that may exist to be replaced:
SELECT ITEM REPLACE(ITEM, '/* AAA: or BBB: or CCC: or DDD: or EEE: */', '')
FROM TABLE1
Any help with this would be very appreciated from this SQL newby!
Look at this query (sqlfiddle: online query):
select t1.ID, ISNULL(REPLACE(t1.Item, t2.Thing, ''), t1.Item) AS THING
from table1 t1
left outer join table2 t2 on (CHARINDEX(t2.Thing, t1.Item) != 0);
Let's say I have table orders
id name
1 order1
2 order2
3 order3
and subtable items
id parent amount price
1 1 1 10
2 1 3 20
3 2 2 5
4 2 5 1
I would like to create query with order with added column value. it should calculate order with all relevant items
id name value
1 order1 70
2 order2 15
3 order3 0
Is this possible with TSQL
GROUP BY and SUM would do it, need to use left join and isnull as you don't have items for all orders.
SELECT o.id, o.name, isnull(sum(i.amount*i.price),0) as value
FROM orders o
left join items i
on o.id = i.parent
group by o.id, o.name
I think you're looking for something like this
SELECT o.name, i.Value FROM orders o WITH (NOLOCK)
LEFT JOIN (SELECT parent, SUM(price) AS Value FROM items WITH (NOLOCK) GROUP BY parent) i
ON o.id = i.parent
...seems like RADAR beat me to the answer.
EDIT: missing the ON line.
Let us consider that we have Categories (with PK as CategoryId) and Products (with PK as ProductId). Also, assume that every Category can relate to its parent category (using ParentCategoryId column in Categories).
How can I get Category wise product count? The parent category should include the count of all products of all of its sub-categories as well.
Any easier way to do?
sounds like what you are asking for would be a good use for with rollup
select cola, colb, SUM(colc) AS sumc
from table
group by cola, colb
with rollup
This would give a sum for colb and a rollup sum for cola. Example result below. Hope the formatting works. The null values are the rollup sums for the group.
cola colb sumc
1 a 1
1 b 4
1 NULL 5
2 c 2
2 d 3
2 NULL 5
NULL NULL 10
Give it a go and let me know if that has worked.
--EDIT
OK i think ive got this as it is working on a small test set i am using. Ive started to see a place where i need this myself so thanks for asking the question. I will admit this is a bit messy but should work for any number of levels and will only return the sum at the highest level.
I made an assumption that there is a number field in products.
with x
as (
select c.CategoryID, c.parentid, p.number, cast(c.CategoryID as varchar(8000)) as grp, c.CategoryID as thisid
from Categories as c
join Products as p on p.Categoryid = c.CategoryID
union all
select c.CategoryID, c.parentid, p.number, cast(c.CategoryID as varchar(8000))+'.'+x.grp , x.thisid
from Categories as c
join Products as p on p.Categoryid = c.CategoryID
join x on x.parentid = c.CategoryID
)
select x.CategoryID, SUM(x.number) as Amount
from x
left join Categories a on (a.CategoryID = LEFT(x.grp, case when charindex('.',x.grp)-1 > 0 then charindex('.',x.grp)-1 else 0 end))
or (a.CategoryID = x.thisid)
where a.parentid = 0
group by x.CategoryID
Assuming that Products can only point to a subcategory, here's a probable solution to the problem:
SELECT
cp.CategoryId,
ProductCount = COUNT(*)
FROM Products p
INNER JOIN Categories cc ON p.CategoryId = cc.CategoryId
INNER JOIN Categories cp ON cc.ParentCategoryId = cp.CategoryId
GROUP BY cp.CategoryId
But if the above assumption is wrong and a product can reference a parent category directly as well as a subcategory, then here's how you could count the products in this case:
SELECT
CategoryId = ISNULL(c2.CategoryId, c1.CategoryId),
ProductCount = COUNT(*)
FROM Products p
INNER JOIN Categories c1 ON p.CategoryId = c1.CategoryId
LEFT JOIN Categories c2 ON c1.ParentCategoryId = c2.CategoryId
GROUP BY ISNULL(c2.CategoryId, c1.CategoryId)
EDIT
This should work for 3 levels of hierarchy of categories (category, sub-category, sub-sub-category).
SELECT
CategoryId = COALESCE(c3.CategoryId, c2.CategoryId, c1.CategoryId),
ProductCount = COUNT(*)
FROM Products p
INNER JOIN Categories c1 ON p.CategoryId = c1.CategoryId
LEFT JOIN Categories c2 ON c1.ParentCategoryId = c2.CategoryId
LEFT JOIN Categories c3 ON c2.ParentCategoryId = c3.CategoryId
GROUP BY ISNULL(c3.CategoryId, c2.CategoryId, c1.CategoryId)
COALESCE picks the first non-NULL component. If the category is a child, it picks c3.Category, which is its grand-parent, if a parent, then its parent c2.Category is chosen, otherwise it's a grand-parent (c1.CategoryId).
In the end, it selects only grand-parent categories, and shows product count for them that includes all the subcategories of all levels.
I have a problem in T-SQL that I find difficult to solve.
I have a table with groups of records, grouped by key1 and key2. I order each group chronologically by date. For each record, I want to see if there existed a record before (within the group and with lower date) for which the field "datafield" forms an allowed combination with the current record's "datafield". For the allowed combinations, I have a table called AllowedCombinationsTable.
I wrote following code to achieve it:
WITH Source AS (
SELECT key1, key2, datafield, date1,
ROW_NUMBER() OVER(PARTITION BY key1, key2 ORDER BY date1 ASC) AS dateorder
FROM table
)
SELECT L.key1, L.key2, L.datafield, DC.datafield2
FROM Source AS L
LEFT JOIN AllowedDataCombinationsTable DC
ON D.datafield1 = L.datafield
LEFT JOIN Source AS R
ON R.Key1 = L.Key1
AND R.Key2 = L.Key2
AND R.dateorder < L.dateorder
AND DC.datafield2 = L.datafield
-- AND "pick the one record with lowest dateorder"
Now for each of these possible combination records, I want to pick the first one (see placeholder in code). How can I do it most efficiently?
EDIT: OK let's say for the source, only showing group (1, 1):
**Key1 Key2 Datafield Date DateOrder**
1 1 "Horse" 1-Jan-2010 1
1 1 "Horse" 2-Jan-2010 2
1 1 "Sheep" 3-Jan-2010 3
1 1 "Dog" 4-Jan-2010 4
1 1 "Cat" 5-Jan-2010 5
AllowedCombinationsTable:
**Datafield1 Datafield**
Cat Sheep (and Sheep Cat)
Cat Horse (and Horse Cat)
Dog Horse (and Horse Dog)
After my join I have now:
**Key1 Key2 Datafield Date DateOrder JoinedCombination JoinedCombinationDateOrder**
1 1 "Horse" 1-Jan-2010 1 NULL NULL
1 1 "Horse" 2-Jan-2010 2 NULL NULL
1 1 "Sheep" 3-Jan-2010 3 NULL NULL
1 1 "Dog" 4-Jan-2010 4 "Horse" 1
1 1 "Dog" 4-Jan-2010 4 "Horse" 2
1 1 "Cat" 5-Jan-2010 5 "Horse" 1
1 1 "Cat" 5-Jan-2010 5 "Horse" 2
1 1 "Cat" 5-Jan-2010 5 "Sheep" 3
I want to display only the first "Horse" for record 4 "Dog", and also only the first "Horse" for record 5 "Cat".
Get it? ;)
I think this may do it--don't have data set up to test the query with. Check the comments for rationale.
WITH Source AS (
SELECT key1, key2, datafield, date1,
ROW_NUMBER() OVER(PARTITION BY key1, key2 ORDER BY date1 ASC) AS dateorder
FROM table
)
SELECT L.key1, L.key2, L.datafield, DC.datafield2
FROM Source AS L
LEFT JOIN AllowedDataCombinationsTable DC
ON DC.datafield1 = L.datafield -- DC Alias
LEFT JOIN Source AS R
ON R.Key1 = L.Key1
AND R.Key2 = L.Key2
AND DC.datafield2 = R.datafield -- Changed alias from L to R
AND R.dateorder = 1 -- Pick out lowest one
AND R.dateorder < L.dateorder -- Make sure it's not the same one
Well, I don't use WITH or OVER, so this is a different approach.. I might be over-simplifying something, but without having the data in front of me this is what I came up with:
SELECT distinct a.Key1, a.Key2, a.Datafield,
ISNULL(b.Datafield,'') as Datafield1,
ISNULL(b.Date,a.Date) as `Date`,
MIN(a.DateOrder) as DateOrder
FROM Source a
LEFT JOIN Source b
ON a.Key1 = b.Key1
AND a.Key2 = b.Key2
AND a.Dateorder <> b.Dateorder
LEFT JOIN AllowedDataCombinationsTable c
ON a.Datafield = c.Datafield
AND b.Datafield = c.Datafield1
GROUP BY a.Key1, a.Key2, a.Datafield, ISNULL(b.Datafield,''), ISNULL(b.Date,a.Date)